aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/cxx/compile.cxx49
-rw-r--r--build2/utility57
-rw-r--r--build2/utility.cxx123
-rw-r--r--build2/utility.ixx31
4 files changed, 242 insertions, 18 deletions
diff --git a/build2/cxx/compile.cxx b/build2/cxx/compile.cxx
index 730ab5a..a2990fb 100644
--- a/build2/cxx/compile.cxx
+++ b/build2/cxx/compile.cxx
@@ -701,6 +701,16 @@ namespace build2
if (cid == "msvc")
{
args.push_back ("/nologo");
+
+ // See perform_update() for details on overriding the default
+ // exceptions and runtime.
+ //
+ if (!find_option_prefix ("/EH", args))
+ args.push_back ("/EHsc");
+
+ if (!find_option_prefixes ({"/MD", "/MT"}, args))
+ args.push_back ("/MD");
+
args.push_back ("/EP"); // Preprocess to stdout.
args.push_back ("/TP"); // Preprocess as C++.
args.push_back ("/showIncludes"); // Goes to sterr becasue of /EP.
@@ -1288,14 +1298,45 @@ namespace build2
if (cid == "msvc")
{
+ // The /F*: option variants with separate names only became available
+ // in VS2013/12.0. Why do we bother? Because the command line suddenly
+ // becomes readable.
+ //
uint64_t cver (cast<uint64_t> (rs["cxx.version.major"]));
if (verb < 3)
args.push_back ("/nologo");
- // The /F*: option variants with separate names only became available
- // in VS2013/12.0. Why do we bother? Because the command line suddenly
- // becomes readable.
+ // While we want to keep the low-level build as "pure" as possible,
+ // the two misguided defaults, exceptions and runtime, just have to be
+ // fixed. Otherwise the default build is pretty much unusable. But we
+ // also make sure that the user can easily disable our defaults: if we
+ // see any relevant options explicitly specified, we take our hands
+ // off.
+ //
+ if (!find_option_prefix ("/EH", args))
+ args.push_back ("/EHsc");
+
+ // The runtime is a bit more interesting. At first it may seem like a
+ // good idea to be a bit clever and use the static runtime if we are
+ // building obja{}. And for obje{} we could decide which runtime to
+ // use based on the library link order: if it is static-only, then we
+ // could assume the static runtime. But it is indeed too clever: when
+ // building liba{} we have no idea who is going to use it. It could be
+ // an exe{} that links both static and shared libraries (and is
+ // therefore built with the shared runtime). And to safely use the
+ // static runtime, everything must be built with /MT and there should
+ // be no DLLs in the picture. So we are going to play it safe and
+ // always default to the shared runtime.
+ //
+ // In a similar vein, it would seem reasonable to use the debug runtime
+ // if we are compiling with debug. But, again, there will be fireworks
+ // if we have some projects built with debug and some without and then
+ // we try to link them together (which is not an unreasonable thing to
+ // do). So by default we will always use the release runtime.
+ //
+ if (!find_option_prefixes ({"/MD", "/MT"}, args))
+ args.push_back ("/MD");
// The presence of /Zi or /ZI causes the compiler to write debug info
// to the .pdb file. By default it is a shared file called vcNN.pdb
@@ -1312,7 +1353,7 @@ namespace build2
// Note also that what we are doing here appears to be incompatible
// with PCH (/Y* options) and /Gm (minimal rebuild).
//
- if (find_option ("/Zi", args) || find_option ("/ZI", args))
+ if (find_options ({"/Zi", "/ZI"}, args))
{
if (cver >= 18)
args.push_back ("/Fd:");
diff --git a/build2/utility b/build2/utility
index 29dca77..4da422b 100644
--- a/build2/utility
+++ b/build2/utility
@@ -166,8 +166,8 @@ namespace build2
void
hash_options (sha256&, const strings&);
- // Check if a specified option is present in the variable or value.
- // T is either target or scope.
+ // Check if a specified option is present in the variable or value. T is
+ // either target or scope.
//
template <typename T>
bool
@@ -185,6 +185,59 @@ namespace build2
bool
find_option (const char* option, const cstrings&, bool ignore_case = false);
+ // As above but look for several options.
+ //
+ template <typename T>
+ bool
+ find_options (initializer_list<const char*>, T&, const char*, bool = false);
+
+ bool
+ find_options (initializer_list<const char*>, const lookup&, bool = false);
+
+ bool
+ find_options (initializer_list<const char*>, const strings&, bool = false);
+
+ bool
+ find_options (initializer_list<const char*>, const cstrings&, bool = false);
+
+ // As above but look for an option that has the specified prefix.
+ //
+ template <typename T>
+ bool
+ find_option_prefix (const char* prefix, T&, const char*, bool = false);
+
+ bool
+ find_option_prefix (const char* prefix, const lookup&, bool = false);
+
+ bool
+ find_option_prefix (const char* prefix, const strings&, bool = false);
+
+ bool
+ find_option_prefix (const char* prefix, const cstrings&, bool = false);
+
+ // As above but look for several option prefixes.
+ //
+ template <typename T>
+ bool
+ find_option_prefixes (initializer_list<const char*>,
+ T&,
+ const char*,
+ bool = false);
+
+ bool
+ find_option_prefixes (initializer_list<const char*>,
+ const lookup&, bool = false);
+
+ bool
+ find_option_prefixes (initializer_list<const char*>,
+ const strings&,
+ bool = false);
+
+ bool
+ find_option_prefixes (initializer_list<const char*>,
+ const cstrings&,
+ bool = false);
+
// Parse version string in the X.Y.Z[-{a|b}N] to a version integer in the
// AABBCCDD form, where:
//
diff --git a/build2/utility.cxx b/build2/utility.cxx
index 87a2749..46741a3 100644
--- a/build2/utility.cxx
+++ b/build2/utility.cxx
@@ -4,6 +4,7 @@
#include <build2/utility>
+#include <cstring> // strlen(), str[n]cmp()
#include <cstdlib> // strtol()
#include <iostream> // cerr
@@ -161,35 +162,137 @@ namespace build2
}
bool
- find_option (const char* option, const lookup& l, bool ic)
+ find_option (const char* o, const lookup& l, bool ic)
{
- return l && find_option (option, cast<strings> (l), ic);
+ return l && find_option (o, cast<strings> (l), ic);
}
bool
- find_option (const char* option, const strings& strs, bool)
+ find_option (const char* o, const strings& strs, bool)
{
//@@ CASE ignore case
for (const string& s: strs)
- {
- if (s == option)
+ if (s == o)
return true;
- }
return false;
}
bool
- find_option (const char* option, const cstrings& cstrs, bool)
+ find_option (const char* o, const cstrings& cstrs, bool)
{
//@@ CASE ignore case
for (const char* s: cstrs)
- {
- if (s != nullptr && strcmp (s, option) == 0)
+ if (s != nullptr && strcmp (s, o) == 0)
return true;
- }
+
+ return false;
+ }
+
+ bool
+ find_options (initializer_list<const char*> os, const lookup& l, bool ic)
+ {
+ return l && find_options (os, cast<strings> (l), ic);
+ }
+
+ bool
+ find_options (initializer_list<const char*> os, const strings& strs, bool)
+ {
+ //@@ CASE ignore case
+
+ for (const string& s: strs)
+ for (const char* o: os)
+ if (s == o)
+ return true;
+
+ return false;
+ }
+
+ bool
+ find_options (initializer_list<const char*> os, const cstrings& cstrs, bool)
+ {
+ //@@ CASE ignore case
+
+ for (const char* s: cstrs)
+ if (s != nullptr)
+ for (const char* o: os)
+ if (strcmp (s, o) == 0)
+ return true;
+
+ return false;
+ }
+
+ bool
+ find_option_prefix (const char* p, const lookup& l, bool ic)
+ {
+ return l && find_option_prefix (p, cast<strings> (l), ic);
+ }
+
+ bool
+ find_option_prefix (const char* p, const strings& strs, bool)
+ {
+ //@@ CASE ignore case
+
+ size_t n (strlen (p));
+
+ for (const string& s: strs)
+ if (s.compare (0, n, p) == 0)
+ return true;
+
+ return false;
+ }
+
+ bool
+ find_option_prefix (const char* p, const cstrings& cstrs, bool)
+ {
+ //@@ CASE ignore case
+
+ size_t n (strlen (p));
+
+ for (const char* s: cstrs)
+ if (s != nullptr && strncmp (s, p, n) == 0)
+ return true;
+
+ return false;
+ }
+
+ bool
+ find_option_prefixes (initializer_list<const char*> ps,
+ const lookup& l,
+ bool ic)
+ {
+ return l && find_option_prefixes (ps, cast<strings> (l), ic);
+ }
+
+ bool
+ find_option_prefixes (initializer_list<const char*> ps,
+ const strings& strs,
+ bool)
+ {
+ //@@ CASE ignore case
+
+ for (const string& s: strs)
+ for (const char* p: ps)
+ if (s.compare (0, strlen (p), p) == 0)
+ return true;
+
+ return false;
+ }
+
+ bool
+ find_option_prefixes (initializer_list<const char*> ps,
+ const cstrings& cstrs,
+ bool)
+ {
+ //@@ CASE ignore case
+
+ for (const char* s: cstrs)
+ if (s != nullptr)
+ for (const char* p: ps)
+ if (strncmp (s, p, strlen (p)) == 0)
+ return true;
return false;
}
diff --git a/build2/utility.ixx b/build2/utility.ixx
index d215ea3..f957875 100644
--- a/build2/utility.ixx
+++ b/build2/utility.ixx
@@ -50,8 +50,35 @@ namespace build2
template <typename T>
inline bool
- find_option (const char* option, T& s, const char* var, bool ic)
+ find_option (const char* o, T& s, const char* var, bool ic)
{
- return find_option (option, s[var], ic);
+ return find_option (o, s[var], ic);
+ }
+
+ template <typename T>
+ inline bool
+ find_options (initializer_list<const char*> os,
+ T& s,
+ const char* var,
+ bool ic)
+ {
+ return find_options (os, s[var], ic);
+ }
+
+ template <typename T>
+ inline bool
+ find_option_prefix (const char* p, T& s, const char* var, bool ic)
+ {
+ return find_option_prefix (p, s[var], ic);
+ }
+
+ template <typename T>
+ inline bool
+ find_option_prefixes (initializer_list<const char*> ps,
+ T& s,
+ const char* var,
+ bool ic)
+ {
+ return find_option_prefixes (ps, s[var], ic);
}
}