Răsfoiți Sursa

SCons: Detect msvc compiler version

• C standard now passed on msvc if the version is supported
Thaddeus Crews 1 an în urmă
părinte
comite
1043c00137
2 a modificat fișierele cu 61 adăugiri și 34 ștergeri
  1. 44 30
      SConstruct
  2. 17 4
      methods.py

+ 44 - 30
SConstruct

@@ -640,25 +640,18 @@ if env.dev_build:
     print("NOTE: Developer build, with debug optimization level and debug symbols (unless overridden).")
 
 # Enforce our minimal compiler version requirements
-cc_version = methods.get_compiler_version(env) or {
-    "major": None,
-    "minor": None,
-    "patch": None,
-    "metadata1": None,
-    "metadata2": None,
-    "date": None,
-}
-cc_version_major = int(cc_version["major"] or -1)
-cc_version_minor = int(cc_version["minor"] or -1)
-cc_version_metadata1 = cc_version["metadata1"] or ""
-
-if methods.using_gcc(env):
-    if cc_version_major == -1:
-        print_warning(
-            "Couldn't detect compiler version, skipping version checks. "
-            "Build may fail if the compiler doesn't support C++17 fully."
-        )
-    elif cc_version_major < 9:
+cc_version = methods.get_compiler_version(env)
+cc_version_major = cc_version["major"]
+cc_version_minor = cc_version["minor"]
+cc_version_metadata1 = cc_version["metadata1"]
+
+if cc_version_major == -1:
+    print_warning(
+        "Couldn't detect compiler version, skipping version checks. "
+        "Build may fail if the compiler doesn't support C++17 fully."
+    )
+elif methods.using_gcc(env):
+    if cc_version_major < 9:
         print_error(
             "Detected GCC version older than 9, which does not fully support "
             "C++17, or has bugs when compiling Godot. Supported versions are 9 "
@@ -678,17 +671,12 @@ if methods.using_gcc(env):
         print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
         env["debug_paths_relative"] = False
 elif methods.using_clang(env):
-    if cc_version_major == -1:
-        print_warning(
-            "Couldn't detect compiler version, skipping version checks. "
-            "Build may fail if the compiler doesn't support C++17 fully."
-        )
     # Apple LLVM versions differ from upstream LLVM version \o/, compare
     # in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
-    elif env["platform"] == "macos" or env["platform"] == "ios":
+    if env["platform"] == "macos" or env["platform"] == "ios":
         vanilla = methods.is_vanilla_clang(env)
         if vanilla and cc_version_major < 6:
-            print_warning(
+            print_error(
                 "Detected Clang version older than 6, which does not fully support "
                 "C++17. Supported versions are Clang 6 and later."
             )
@@ -713,6 +701,28 @@ elif methods.using_clang(env):
     if env["debug_paths_relative"] and cc_version_major < 10:
         print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
         env["debug_paths_relative"] = False
+elif env.msvc:
+    # Ensure latest minor builds of Visual Studio 2017/2019.
+    # https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
+    if cc_version_major == 16 and cc_version_minor < 11:
+        print_error(
+            "Detected Visual Studio 2019 version older than 16.11, which has bugs "
+            "when compiling Godot. Use a newer VS2019 version, or VS2022."
+        )
+        Exit(255)
+    if cc_version_major == 15 and cc_version_minor < 9:
+        print_error(
+            "Detected Visual Studio 2017 version older than 15.9, which has bugs "
+            "when compiling Godot. Use a newer VS2017 version, or VS2019/VS2022."
+        )
+        Exit(255)
+    if cc_version_major < 15:
+        print_error(
+            "Detected Visual Studio 2015 or earlier, which is unsupported in Godot. "
+            "Supported versions are Visual Studio 2017 and later."
+        )
+        Exit(255)
+
 
 # Set optimize and debug_symbols flags.
 # "custom" means do nothing and let users set their own optimization flags.
@@ -790,13 +800,17 @@ if env["lto"] != "none":
 # This needs to come after `configure`, otherwise we don't have env.msvc.
 if not env.msvc:
     # Specifying GNU extensions support explicitly, which are supported by
-    # both GCC and Clang. Both currently default to gnu11 and gnu++14.
+    # both GCC and Clang. Both currently default to gnu11 and gnu++17.
     env.Prepend(CFLAGS=["-std=gnu11"])
     env.Prepend(CXXFLAGS=["-std=gnu++17"])
 else:
-    # MSVC doesn't have clear C standard support, /std only covers C++.
-    # We apply it to CCFLAGS (both C and C++ code) in case it impacts C features.
-    env.Prepend(CCFLAGS=["/std:c++17"])
+    # MSVC started offering C standard support with Visual Studio 2019 16.8, which covers all
+    # of our supported VS2019 & VS2022 versions; VS2017 will only pass the C++ standard.
+    env.Prepend(CXXFLAGS=["/std:c++17"])
+    if cc_version_major < 16:
+        print_warning("Visual Studio 2017 cannot specify a C-Standard.")
+    else:
+        env.Prepend(CFLAGS=["/std:c11"])
     # MSVC is non-conforming with the C++ standard by default, so we enable more conformance.
     # Note that this is still not complete conformance, as certain Windows-related headers
     # don't compile under complete conformance.

+ 17 - 4
methods.py

@@ -795,9 +795,9 @@ def get_compiler_version(env):
         "major": -1,
         "minor": -1,
         "patch": -1,
-        "metadata1": None,
-        "metadata2": None,
-        "date": None,
+        "metadata1": "",
+        "metadata2": "",
+        "date": "",
         "apple_major": -1,
         "apple_minor": -1,
         "apple_patch1": -1,
@@ -806,7 +806,20 @@ def get_compiler_version(env):
     }
 
     if env.msvc and not using_clang(env):
-        # TODO: Implement for MSVC
+        try:
+            args = [env["VSWHERE"], "-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"]
+            version = subprocess.check_output(args, encoding="utf-8").strip()
+            for line in version.splitlines():
+                split = line.split(":", 1)
+                if split[0] == "catalog_productDisplayVersion":
+                    sem_ver = split[1].split(".")
+                    ret["major"] = int(sem_ver[0])
+                    ret["minor"] = int(sem_ver[1])
+                    ret["patch"] = int(sem_ver[2])
+                if split[0] == "catalog_buildVersion":
+                    ret["metadata1"] = split[1]
+        except (subprocess.CalledProcessError, OSError):
+            print_warning("Couldn't find vswhere to determine compiler version.")
         return ret
 
     # Not using -dumpversion as some GCC distros only return major, and