aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-05-30 10:23:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-05-30 10:23:27 +0200
commit49fd34cb82d8edae683526a5d9fdd3c86136e646 (patch)
treee5e21a1d451e813ae18033066002019998ba5b76
parentac379d5c0a7d8a7382649f3988eb86474d5e4a13 (diff)
Rework C/C++ standard translation in preparation for experimental/modules
Also fix bug in clang-apple versioning.
-rw-r--r--build2/c/init.cxx104
-rw-r--r--build2/cc/common.hxx20
-rw-r--r--build2/cc/compile.cxx11
-rw-r--r--build2/cc/gcc.cxx2
-rw-r--r--build2/cc/guess.cxx45
-rw-r--r--build2/cc/link.cxx2
-rw-r--r--build2/cc/module.cxx11
-rw-r--r--build2/cc/module.hxx11
-rw-r--r--build2/cxx/init.cxx217
9 files changed, 232 insertions, 191 deletions
diff --git a/build2/c/init.cxx b/build2/c/init.cxx
index ada8596..998bc40 100644
--- a/build2/c/init.cxx
+++ b/build2/c/init.cxx
@@ -20,6 +20,7 @@ namespace build2
{
namespace c
{
+ using cc::compiler_id;
using cc::compiler_info;
class config_module: public cc::config_module
@@ -29,64 +30,77 @@ namespace build2
config_module (config_data&& d)
: config_data (move (d)), cc::config_module (move (d)) {}
- string
+ strings
translate_std (const compiler_info&,
scope&,
- const string&) const override;
+ const string*) const override;
};
using cc::module;
- string config_module::
- translate_std (const compiler_info& ci, scope& rs, const string& v) const
+ strings config_module::
+ translate_std (const compiler_info& ci, scope& rs, const string* v) const
{
- string r;
+ strings r;
- if (ci.id.type == "msvc")
+ switch (ci.id.value ())
{
- // Standard-wise, with VC you get what you get. The question is
- // whether we should verify that the requested standard is provided by
- // this VC version. And if so, from which version should we say VC
- // supports 90, 99, and 11? We should probably be as loose as possible
- // here since the author will always be able to tighten (but not
- // loosen) this in the buildfile (i.e., detect unsupported versions).
- //
- // The state of affairs seem to be (from Herb Sutter's blog):
- //
- // 10.0 - most of C95 plus a few C99 features
- // 11.0 - partial support for the C++11 subset of C11
- // 12.0 - more C11 features from the C++11 subset, most of C99
- //
- // So let's say C99 is supported from 10.0 and C11 from 11.0. And C90
- // is supported by everything we care to support.
- //
- if (v != "90")
+ case compiler_id::msvc:
{
- uint64_t cver (ci.version.major);
-
- if ((v == "99" && cver < 16) || // Since VS2010/10.0.
- (v == "11" && cver < 17)) // Since VS2012/11.0.
+ // Standard-wise, with VC you get what you get. The question is
+ // whether we should verify that the requested standard is provided
+ // by this VC version. And if so, from which version should we say
+ // VC supports 90, 99, and 11? We should probably be as loose as
+ // possible here since the author will always be able to tighten
+ // (but not loosen) this in the buildfile (i.e., detect unsupported
+ // versions).
+ //
+ // The state of affairs seem to be (from Herb Sutter's blog):
+ //
+ // 10.0 - most of C95 plus a few C99 features
+ // 11.0 - partial support for the C++11 subset of C11
+ // 12.0 - more C11 features from the C++11 subset, most of C99
+ //
+ // So let's say C99 is supported from 10.0 and C11 from 11.0. And
+ // C90 is supported by everything we care to support.
+ //
+ if (v == nullptr)
+ ;
+ else if (*v != "90")
{
- fail << "C" << v << " is not supported by " << ci.signature <<
- info << "required by " << project (rs) << '@' << rs.out_path ();
+ uint64_t cver (ci.version.major);
+
+ if ((*v == "99" && cver < 16) || // Since VS2010/10.0.
+ (*v == "11" && cver < 17)) // Since VS2012/11.0.
+ {
+ fail << "C" << *v << " is not supported by " << ci.signature <<
+ info << "required by " << project (rs) << '@' << rs.out_path ();
+ }
}
+ break;
+ }
+ case compiler_id::gcc:
+ case compiler_id::clang:
+ case compiler_id::icc:
+ {
+ // 90 and 89 are the same standard. Translate 99 to 9x and 11 to 1x
+ // for compatibility with older versions of the compilers.
+ //
+ if (v == nullptr)
+ ;
+ else
+ {
+ string o ("-std=");
+
+ if (*v == "90") o += "c90";
+ else if (*v == "99") o += "c9x";
+ else if (*v == "11") o += "c1x";
+ else o += *v; // In case the user specifies e.g., 'gnu11'.
+
+ r.push_back (move (o));
+ }
+ break;
}
- }
- else
- {
- // 90 and 89 are the same standard. Translate 99 to 9x and 11 to 1x
- // for compatibility with older versions of the compilers.
- //
- r = "-std=";
-
- if (v == "90")
- r += "c90";
- else if (v == "99")
- r += "c9x";
- else if (v == "11")
- r += "c1x";
- else
- r += v; // In case the user specifies something like 'gnu11'.
}
return r;
diff --git a/build2/cc/common.hxx b/build2/cc/common.hxx
index 55e6675..fa6ec5a 100644
--- a/build2/cc/common.hxx
+++ b/build2/cc/common.hxx
@@ -112,7 +112,7 @@ namespace build2
const string& tsys; // x.target.system
const string& tclass; // x.target.class
- const string& tstd; // Translated x_std value (can be empty).
+ const strings& tstd; // Translated x_std value (options).
const process_path* pkgconfig; // pkgconfig.path (can be NULL).
const dir_paths& sys_lib_dirs; // x.sys_lib_dirs
@@ -153,7 +153,7 @@ namespace build2
uint64_t mj, uint64_t mi,
const process_path& path,
const target_triplet& tg,
- const string& std,
+ const strings& std,
const process_path* pkgc,
const dir_paths& sld,
const dir_paths& sid,
@@ -177,22 +177,6 @@ namespace build2
public:
common (data&& d): data (move (d)) {}
- // Language standard (x.std) mapping.
- //
- void
- append_std (cstrings& args) const
- {
- if (!tstd.empty ())
- args.push_back (tstd.c_str ());
- }
-
- void
- hash_std (sha256& cs) const
- {
- if (!tstd.empty ())
- cs.append (tstd);
- }
-
// Library handling.
//
public:
diff --git a/build2/cc/compile.cxx b/build2/cc/compile.cxx
index 5a95169..ce96e00 100644
--- a/build2/cc/compile.cxx
+++ b/build2/cc/compile.cxx
@@ -531,7 +531,7 @@ namespace build2
hash_options (cs, t, c_coptions);
hash_options (cs, t, x_coptions);
- hash_std (cs);
+ hash_options (cs, tstd);
if (ct == otype::s)
{
@@ -1183,8 +1183,7 @@ namespace build2
//
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
-
- append_std (args);
+ append_options (args, tstd);
if (cid == compiler_id::msvc)
{
@@ -2057,8 +2056,7 @@ namespace build2
//
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
-
- append_std (args);
+ append_options (args, tstd);
if (cid == compiler_id::msvc)
{
@@ -2272,11 +2270,10 @@ namespace build2
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
+ append_options (args, tstd);
string out, out1; // Storage.
- append_std (args);
-
if (cid == compiler_id::msvc)
{
// The /F*: option variants with separate names only became available
diff --git a/build2/cc/gcc.cxx b/build2/cc/gcc.cxx
index b5dd236..7f52a91 100644
--- a/build2/cc/gcc.cxx
+++ b/build2/cc/gcc.cxx
@@ -38,7 +38,7 @@ namespace build2
args.push_back (xc.recall_string ());
append_options (args, rs, c_coptions);
append_options (args, rs, x_coptions);
- if (!tstd.empty ()) args.push_back (tstd.c_str ());
+ append_options (args, tstd);
append_options (args, rs, c_loptions);
append_options (args, rs, x_loptions);
args.push_back ("-print-search-dirs");
diff --git a/build2/cc/guess.cxx b/build2/cc/guess.cxx
index 9f14661..7dde013 100644
--- a/build2/cc/guess.cxx
+++ b/build2/cc/guess.cxx
@@ -1096,28 +1096,33 @@ namespace build2
compiler_info r;
const compiler_id& id (gr.id);
- if (id.type == "gcc")
+ switch (id.value ())
{
- assert (id.variant.empty ());
- r = guess_gcc (xl, xc, c_coptions, x_coptions, move (gr));
- }
- else if (id.type == "clang")
- {
- assert (id.variant.empty () || id.variant == "apple");
- r = guess_clang (xl, xc, c_coptions, x_coptions, move (gr));
- }
- else if (id.type == "icc")
- {
- assert (id.variant.empty ());
- r = guess_icc (xl, xc, c_coptions, x_coptions, move (gr));
- }
- else if (id.type == "msvc")
- {
- assert (id.variant.empty ());
- r = guess_msvc (xl, xc, c_coptions, x_coptions, move (gr));
+ case compiler_id::gcc:
+ {
+ assert (id.variant.empty ());
+ r = guess_gcc (xl, xc, c_coptions, x_coptions, move (gr));
+ break;
+ }
+ case compiler_id::clang:
+ {
+ assert (id.variant.empty () || id.variant == "apple");
+ r = guess_clang (xl, xc, c_coptions, x_coptions, move (gr));
+ break;
+ }
+ case compiler_id::msvc:
+ {
+ assert (id.variant.empty ());
+ r = guess_msvc (xl, xc, c_coptions, x_coptions, move (gr));
+ break;
+ }
+ case compiler_id::icc:
+ {
+ assert (id.variant.empty ());
+ r = guess_icc (xl, xc, c_coptions, x_coptions, move (gr));
+ break;
+ }
}
- else
- assert (false);
// Derive binutils pattern unless this has already been done by the
// compiler-specific code.
diff --git a/build2/cc/link.cxx b/build2/cc/link.cxx
index 91c2739..5c75d34 100644
--- a/build2/cc/link.cxx
+++ b/build2/cc/link.cxx
@@ -1192,7 +1192,7 @@ namespace build2
{
append_options (args, t, c_coptions);
append_options (args, t, x_coptions);
- append_std (args);
+ append_options (args, tstd);
}
append_options (args, t, c_loptions);
diff --git a/build2/cc/module.cxx b/build2/cc/module.cxx
index 885d6c7..cdc45e5 100644
--- a/build2/cc/module.cxx
+++ b/build2/cc/module.cxx
@@ -118,10 +118,9 @@ namespace build2
}
}
- // Translate x_std value (if any) to the compiler option (if any).
+ // Translate x_std value (if any) to the compiler option(s) (if any).
//
- if (auto l = rs[x_std])
- tstd = translate_std (ci, rs, cast<string> (*l));
+ tstd = translate_std (ci, rs, cast_null<string> (rs[x_std]));
// Extract system library search paths from the compiler and determine
// additional system include search paths.
@@ -129,7 +128,7 @@ namespace build2
dir_paths lib_dirs;
dir_paths inc_dirs;
- if (ci.id.type == "msvc")
+ if (ci.id.value () == compiler_id::msvc)
lib_dirs = msvc_library_search_paths (ci.path, rs);
else
{
@@ -188,7 +187,9 @@ namespace build2
if (!tstd.empty ())
{
- dr << " std " << tstd << '\n';
+ dr << " std "; // One less space.
+ for (const string& o: tstd) dr << ' ' << o;
+ dr << '\n';
}
if (!ci.cc_pattern.empty ()) // bin_pattern printed by bin
diff --git a/build2/cc/module.hxx b/build2/cc/module.hxx
index eaa82eb..db17998 100644
--- a/build2/cc/module.hxx
+++ b/build2/cc/module.hxx
@@ -32,13 +32,14 @@ namespace build2
void
init (scope&, const location&, const variable_map&);
- // Translate the x.std value to the standard-selecting option if there
- // is any.
+ // Translate the x.std value (if any) to the standard-selecting
+ // option(s) (if any). May also check/set x.features.* variables on the
+ // root scope.
//
- virtual string
- translate_std (const compiler_info&, scope&, const string&) const = 0;
+ virtual strings
+ translate_std (const compiler_info&, scope&, const string*) const = 0;
- string tstd;
+ strings tstd;
compiler_id::value_type cid;
diff --git a/build2/cxx/init.cxx b/build2/cxx/init.cxx
index 72a8fe5..a8706a3 100644
--- a/build2/cxx/init.cxx
+++ b/build2/cxx/init.cxx
@@ -20,6 +20,7 @@ namespace build2
{
namespace cxx
{
+ using cc::compiler_id;
using cc::compiler_info;
class config_module: public cc::config_module
@@ -29,128 +30,166 @@ namespace build2
config_module (config_data&& d)
: config_data (move (d)), cc::config_module (move (d)) {}
- string
+ strings
translate_std (const compiler_info&,
scope&,
- const string&) const override;
+ const string*) const override;
};
using cc::module;
- string config_module::
- translate_std (const compiler_info& ci, scope& rs, const string& v) const
+ strings config_module::
+ translate_std (const compiler_info& ci, scope& rs, const string* v) const
{
- string r;
+ strings r;
- const string& t (ci.id.type);
+ auto id (ci.id.value ());
uint64_t mj (ci.version.major);
uint64_t mi (ci.version.minor);
uint64_t p (ci.version.patch);
// Translate "latest" to the compiler/version-appropriate option.
//
- if (v == "latest")
+ if (v != nullptr && *v == "latest")
{
- if (t == "msvc")
- {
- // VC14u3 and later has /std:c++latest.
- //
- if (mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))))
- r = "/std:c++latest";
- }
- else if (t == "gcc")
- {
- if (mj >= 5) r = "-std=c++1z"; // 17
- else if (mj == 4 && mi >= 8) r = "-std=c++1y"; // 14
- else if (mj == 4 && mi >= 4) r = "-std=c++0x"; // 11
- }
- else if (t == "clang")
- {
- if (mj > 3 || (mj == 3 && mi >= 5)) r = "-std=c++1z"; // 17
- else if (mj == 3 && mi >= 4) r = "-std=c++1y"; // 14
- else /* ??? */ r = "-std=c++0x"; // 11
- }
- else if (t == "icc")
+ const char* o (nullptr);
+
+ switch (id)
{
- if (mj >= 17) r = "-std=c++1z"; // 17
- else if (mj > 15 || (mj == 15 && p >= 3)) r = "-std=c++1y"; // 14
- else /* ??? */ r = "-std=c++0x"; // 11
+ case compiler_id::msvc:
+ {
+ // VC14u3 and later has /std:c++latest.
+ //
+ if (mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))))
+ o = "/std:c++latest";
+
+ break;
+ }
+ case compiler_id::gcc:
+ {
+ if (mj >= 5) o = "-std=c++1z"; // 17
+ else if (mj == 4 && mi >= 8) o = "-std=c++1y"; // 14
+ else if (mj == 4 && mi >= 4) o = "-std=c++0x"; // 11
+
+ break;
+ }
+ case compiler_id::clang:
+ {
+ // Re-map Apple versions to vanilla Clang based on the following
+ // release point:
+ //
+ // 5.1 -> 3.4
+ // 6.0 -> 3.5
+ //
+ if (ci.id.variant == "apple")
+ {
+ if (mj >= 6) {mj = 3; mi = 5;}
+ else if (mj == 5 && mi >= 1) {mj = 3; mi = 4;}
+ else {mj = 3; mi = 0;}
+ }
+
+ if (mj > 3 || (mj == 3 && mi >= 5)) o = "-std=c++1z"; // 17
+ else if (mj == 3 && mi >= 4) o = "-std=c++1y"; // 14
+ else /* ??? */ o = "-std=c++0x"; // 11
+
+ break;
+ }
+ case compiler_id::icc:
+ {
+ if (mj >= 17) o = "-std=c++1z"; // 17
+ else if (mj > 15 || (mj == 15 && p >= 3)) o = "-std=c++1y"; // 14
+ else /* ??? */ o = "-std=c++0x"; // 11
+
+ break;
+ }
}
- else
- assert (false);
+
+ if (o != nullptr)
+ r.push_back (o);
return r;
}
// Otherwise translate the standard value.
//
- if (t == "msvc")
+ switch (id)
{
- // C++ standard-wise, with VC you got what you got up until 14u2.
- // Starting with 14u3 there is now the /std: switch which defaults
- // to c++14 but can be set to c++latest.
- //
- // The question is also whether we should verify that the requested
- // standard is provided by this VC version. And if so, from which
- // version should we say VC supports 11, 14, and 17? We should
- // probably be as loose as possible here since the author will always
- // be able to tighten (but not loosen) this in the buildfile (i.e.,
- // detect unsupported versions).
- //
- // For now we are not going to bother doing this for C++03.
- //
- if (v != "98" && v != "03")
+ case compiler_id::msvc:
{
- bool sup (false);
-
- if (v == "11") // C++11 since VS2010/10.0.
- {
- sup = mj >= 16;
- }
- else if (v == "14") // C++14 since VS2015/14.0.
- {
- sup = mj >= 19;
- }
- else if (v == "17") // C++17 since VS2015/14.0u2.
+ // C++ standard-wise, with VC you got what you got up until 14u2.
+ // Starting with 14u3 there is now the /std: switch which defaults
+ // to c++14 but can be set to c++latest.
+ //
+ // The question is also whether we should verify that the requested
+ // standard is provided by this VC version. And if so, from which
+ // version should we say VC supports 11, 14, and 17? We should
+ // probably be as loose as possible here since the author will
+ // always be able to tighten (but not loosen) this in the buildfile
+ // (i.e., detect unsupported versions).
+ //
+ // For now we are not going to bother doing this for C++03.
+ //
+ if (v == nullptr)
+ ;
+ else if (*v != "98" && *v != "03")
{
- // Note: the VC15 compiler version is 19.10.
+ bool sup (false);
+
+ if (*v == "11") // C++11 since VS2010/10.0.
+ {
+ sup = mj >= 16;
+ }
+ else if (*v == "14") // C++14 since VS2015/14.0.
+ {
+ sup = mj >= 19;
+ }
+ else if (*v == "17") // C++17 since VS2015/14.0u2.
+ {
+ // Note: the VC15 compiler version is 19.10.
+ //
+ sup = (mj > 19 ||
+ (mj == 19 && (mi > 0 || (mi == 0 && p >= 23918))));
+ }
+
+ if (!sup)
+ fail << "C++" << *v << " is not supported by " << ci.signature <<
+ info << "required by " << project (rs) << '@' << rs.out_path ();
+
+ // VC14u3 and later has /std:
//
- sup = mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 23918)));
+ if (mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))))
+ {
+ if (*v == "17")
+ r.push_back ("/std:c++latest");
+ }
}
-
- if (!sup)
- fail << "C++" << v << " is not supported by " << ci.signature <<
- info << "required by " << project (rs) << '@' << rs.out_path ();
-
- // VC14u3 and later has /std:
+ break;
+ }
+ case compiler_id::gcc:
+ case compiler_id::clang:
+ case compiler_id::icc:
+ {
+ // Translate 11 to 0x, 14 to 1y, and 17 to 1z for compatibility with
+ // older versions of the compilers.
//
- if (mj > 19 || (mj == 19 && (mi > 0 || (mi == 0 && p >= 24215))))
+ if (v == nullptr)
+ ;
+ else
{
- if (v == "17")
- r = "/std:c++latest";
+ string o ("-std=");
+
+ if (*v == "98") o += "c++98";
+ else if (*v == "03") o += "c++03";
+ else if (*v == "11") o += "c++0x";
+ else if (*v == "14") o += "c++1y";
+ else if (*v == "17") o += "c++1z";
+ else o += *v; // In case the user specifies e.g., 'gnu++17'.
+
+ r.push_back (move (o));
}
+ break;
}
}
- else
- {
- // Translate 11 to 0x, 14 to 1y, and 17 to 1z for compatibility with
- // older versions of the compilers.
- //
- r = "-std=";
-
- if (v == "98")
- r += "c++98";
- else if (v == "03")
- r += "c++03";
- else if (v == "11")
- r += "c++0x";
- else if (v == "14")
- r += "c++1y";
- else if (v == "17")
- r += "c++1z";
- else
- r += v; // In case the user specifies something like 'gnu++17'.
- }
return r;
}