diff options
-rw-r--r-- | build2/cxx/compile.cxx | 49 | ||||
-rw-r--r-- | build2/utility | 57 | ||||
-rw-r--r-- | build2/utility.cxx | 123 | ||||
-rw-r--r-- | build2/utility.ixx | 31 |
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); } } |