Browse Source

SCons: Refactor color output implementation

Thaddeus Crews 7 tháng trước cách đây
mục cha
commit
a29294fddc

+ 12 - 32
SConstruct

@@ -5,12 +5,10 @@ EnsureSConsVersion(4, 0)
 EnsurePythonVersion(3, 8)
 
 # System
-import atexit
 import glob
 import os
 import pickle
 import sys
-import time
 from collections import OrderedDict
 from importlib.util import module_from_spec, spec_from_file_location
 from types import ModuleType
@@ -52,13 +50,14 @@ _helper_module("platform_methods", "platform_methods.py")
 _helper_module("version", "version.py")
 _helper_module("core.core_builders", "core/core_builders.py")
 _helper_module("main.main_builders", "main/main_builders.py")
+_helper_module("misc.utility.color", "misc/utility/color.py")
 
 # Local
 import gles3_builders
 import glsl_builders
 import methods
 import scu_builders
-from methods import Ansi, print_error, print_info, print_warning
+from misc.utility.color import STDERR_COLOR, print_error, print_info, print_warning
 from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
 
 if ARGUMENTS.get("target", "editor") == "editor":
@@ -74,8 +73,6 @@ platform_doc_class_path = {}
 platform_exporters = []
 platform_apis = []
 
-time_at_start = time.time()
-
 for x in sorted(glob.glob("platform/*")):
     if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
         continue
@@ -702,6 +699,14 @@ if env["arch"] == "x86_32":
     else:
         env.Append(CCFLAGS=["-msse2"])
 
+# Explicitly specify colored output.
+if methods.using_gcc(env):
+    env.AppendUnique(CCFLAGS=["-fdiagnostics-color" if STDERR_COLOR else "-fno-diagnostics-color"])
+elif methods.using_clang(env) or methods.using_emcc(env):
+    env.AppendUnique(CCFLAGS=["-fcolor-diagnostics" if STDERR_COLOR else "-fno-color-diagnostics"])
+    if sys.platform == "win32":
+        env.AppendUnique(CCFLAGS=["-fansi-escape-codes"])
+
 # Set optimize and debug_symbols flags.
 # "custom" means do nothing and let users set their own optimization flags.
 # Needs to happen after configure to have `env.msvc` defined.
@@ -1086,30 +1091,5 @@ methods.show_progress(env)
 # TODO: replace this with `env.Dump(format="json")`
 # once we start requiring SCons 4.0 as min version.
 methods.dump(env)
-
-
-def print_elapsed_time():
-    elapsed_time_sec = round(time.time() - time_at_start, 2)
-    time_centiseconds = round((elapsed_time_sec % 1) * 100)
-    print(
-        "{}[Time elapsed: {}.{:02}]{}".format(
-            Ansi.GRAY,
-            time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
-            time_centiseconds,
-            Ansi.RESET,
-        )
-    )
-
-
-atexit.register(print_elapsed_time)
-
-
-def purge_flaky_files():
-    paths_to_keep = [env["ninja_file"]]
-    for build_failure in GetBuildFailures():
-        path = build_failure.node.path
-        if os.path.isfile(path) and path not in paths_to_keep:
-            os.remove(path)
-
-
-atexit.register(purge_flaky_files)
+methods.prepare_purge(env)
+methods.prepare_timer()

+ 4 - 3
doc/tools/doc_status.py

@@ -10,14 +10,14 @@ from typing import Dict, List, Set
 
 sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
 
-from methods import COLOR_SUPPORTED, Ansi, toggle_color
+from misc.utility.color import STDOUT_COLOR, Ansi, toggle_color
 
 ################################################################################
 #                                    Config                                    #
 ################################################################################
 
 flags = {
-    "c": COLOR_SUPPORTED,
+    "c": STDOUT_COLOR,
     "b": False,
     "g": False,
     "s": False,
@@ -330,7 +330,8 @@ if flags["u"]:
     table_column_names.append("Docs URL")
     table_columns.append("url")
 
-toggle_color(flags["c"])
+if flags["c"]:
+    toggle_color(True)
 
 ################################################################################
 #                                     Help                                     #

+ 3 - 2
doc/tools/make_rst.py

@@ -13,7 +13,7 @@ from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
 sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
 
 import version
-from methods import Ansi, toggle_color
+from misc.utility.color import Ansi, toggle_color
 
 # $DOCS_URL/path/to/page.html(#fragment-tag)
 GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@@ -697,7 +697,8 @@ def main() -> None:
     )
     args = parser.parse_args()
 
-    toggle_color(args.color)
+    if args.color:
+        toggle_color(True)
 
     # Retrieve heading translations for the given language.
     if not args.dry_run and args.lang != "en":

+ 31 - 113
methods.py

@@ -7,125 +7,16 @@ import re
 import subprocess
 import sys
 from collections import OrderedDict
-from enum import Enum
 from io import StringIO, TextIOWrapper
 from pathlib import Path
-from typing import Final, Generator, List, Optional, Union, cast
+from typing import Generator, List, Optional, Union, cast
+
+from misc.utility.color import print_error, print_info, print_warning
 
 # Get the "Godot" folder name ahead of time
 base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
 base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
 
-################################################################################
-# COLORIZE
-################################################################################
-
-IS_CI: Final[bool] = bool(os.environ.get("CI"))
-IS_TTY: Final[bool] = bool(sys.stdout.isatty())
-
-
-def _color_supported() -> bool:
-    """
-    Enables ANSI escape code support on Windows 10 and later (for colored console output).
-    See here: https://github.com/python/cpython/issues/73245
-    """
-    if sys.platform == "win32" and IS_TTY:
-        try:
-            from ctypes import WinError, byref, windll  # type: ignore
-            from ctypes.wintypes import DWORD  # type: ignore
-
-            stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
-            mode = DWORD(0)
-            if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
-                raise WinError()
-            mode = DWORD(mode.value | 4)
-            if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
-                raise WinError()
-        except (TypeError, OSError) as e:
-            print(f"Failed to enable ANSI escape code support, disabling color output.\n{e}", file=sys.stderr)
-            return False
-
-    return IS_TTY or IS_CI
-
-
-# Colors are disabled in non-TTY environments such as pipes. This means
-# that if output is redirected to a file, it won't contain color codes.
-# Colors are always enabled on continuous integration.
-COLOR_SUPPORTED: Final[bool] = _color_supported()
-_can_color: bool = COLOR_SUPPORTED
-
-
-def toggle_color(value: Optional[bool] = None) -> None:
-    """
-    Explicitly toggle color codes, regardless of support.
-
-    - `value`: An optional boolean to explicitly set the color
-    state instead of toggling.
-    """
-    global _can_color
-    _can_color = value if value is not None else not _can_color
-
-
-class Ansi(Enum):
-    """
-    Enum class for adding ansi colorcodes directly into strings.
-    Automatically converts values to strings representing their
-    internal value, or an empty string in a non-colorized scope.
-    """
-
-    RESET = "\x1b[0m"
-
-    BOLD = "\x1b[1m"
-    DIM = "\x1b[2m"
-    ITALIC = "\x1b[3m"
-    UNDERLINE = "\x1b[4m"
-    STRIKETHROUGH = "\x1b[9m"
-    REGULAR = "\x1b[22;23;24;29m"
-
-    BLACK = "\x1b[30m"
-    RED = "\x1b[31m"
-    GREEN = "\x1b[32m"
-    YELLOW = "\x1b[33m"
-    BLUE = "\x1b[34m"
-    MAGENTA = "\x1b[35m"
-    CYAN = "\x1b[36m"
-    WHITE = "\x1b[37m"
-
-    LIGHT_BLACK = "\x1b[90m"
-    LIGHT_RED = "\x1b[91m"
-    LIGHT_GREEN = "\x1b[92m"
-    LIGHT_YELLOW = "\x1b[93m"
-    LIGHT_BLUE = "\x1b[94m"
-    LIGHT_MAGENTA = "\x1b[95m"
-    LIGHT_CYAN = "\x1b[96m"
-    LIGHT_WHITE = "\x1b[97m"
-
-    GRAY = LIGHT_BLACK if IS_CI else BLACK
-    """
-    Special case. GitHub Actions doesn't convert `BLACK` to gray as expected, but does convert `LIGHT_BLACK`.
-    By implementing `GRAY`, we handle both cases dynamically, while still allowing for explicit values if desired.
-    """
-
-    def __str__(self) -> str:
-        global _can_color
-        return str(self.value) if _can_color else ""
-
-
-def print_info(*values: object) -> None:
-    """Prints a informational message with formatting."""
-    print(f"{Ansi.GRAY}{Ansi.BOLD}INFO:{Ansi.REGULAR}", *values, Ansi.RESET)
-
-
-def print_warning(*values: object) -> None:
-    """Prints a warning message with formatting."""
-    print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
-
-
-def print_error(*values: object) -> None:
-    """Prints an error message with formatting."""
-    print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
-
-
 # Listing all the folders we have converted
 # for SCU in scu_builders.py
 _scu_folders = set()
@@ -505,6 +396,8 @@ def use_windows_spawn_fix(self, platform=None):
 
 
 def no_verbose(env):
+    from misc.utility.color import Ansi
+
     colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
 
     # There is a space before "..." to ensure that source file names can be
@@ -875,7 +768,7 @@ def show_progress(env):
 
             # Progress reporting is not available in non-TTY environments since it
             # messes with the output (for example, when writing to a file).
-            self.display = cast(bool, self.max and env["progress"] and IS_TTY)
+            self.display = cast(bool, self.max and env["progress"] and sys.stdout.isatty())
             if self.display and not self.max:
                 print_info("Performing initial build, progress percentage unavailable!")
 
@@ -1019,6 +912,31 @@ def prepare_cache(env) -> None:
     atexit.register(clean_cache, cache_path, cache_limit, env["verbose"])
 
 
+def prepare_purge(env):
+    from SCons.Script.Main import GetBuildFailures
+
+    def purge_flaky_files():
+        paths_to_keep = [env["ninja_file"]]
+        for build_failure in GetBuildFailures():
+            path = build_failure.node.path
+            if os.path.isfile(path) and path not in paths_to_keep:
+                os.remove(path)
+
+    atexit.register(purge_flaky_files)
+
+
+def prepare_timer():
+    import time
+
+    def print_elapsed_time(time_at_start: float):
+        time_elapsed = time.time() - time_at_start
+        time_formatted = time.strftime("%H:%M:%S", time.gmtime(time_elapsed))
+        time_centiseconds = round((time_elapsed % 1) * 100)
+        print_info(f"Time elapsed: {time_formatted}.{time_centiseconds}")
+
+    atexit.register(print_elapsed_time, time.time())
+
+
 def dump(env):
     # Dumps latest build information for debugging purposes and external tools.
     from json import dump

+ 1 - 1
misc/scripts/install_d3d12_sdk_windows.py

@@ -8,7 +8,7 @@ import urllib.request
 
 sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
 
-from methods import Ansi
+from misc.utility.color import Ansi
 
 # Base Godot dependencies path
 # If cross-compiling (no LOCALAPPDATA), we install in `bin`

+ 130 - 0
misc/utility/color.py

@@ -0,0 +1,130 @@
+from __future__ import annotations
+
+import os
+import sys
+from enum import Enum
+from typing import Final
+
+# Colors are disabled in non-TTY environments such as pipes. This means if output is redirected
+# to a file, it won't contain color codes. Colors are always enabled on continuous integration.
+
+IS_CI: Final[bool] = bool(os.environ.get("CI"))
+STDOUT_TTY: Final[bool] = bool(sys.stdout.isatty())
+STDERR_TTY: Final[bool] = bool(sys.stderr.isatty())
+
+
+def _color_supported(stdout: bool) -> bool:
+    """
+    Validates if the current environment supports colored output. Attempts to enable ANSI escape
+    code support on Windows 10 and later.
+    """
+    if IS_CI:
+        return True
+
+    if sys.platform != "win32":
+        return STDOUT_TTY if stdout else STDERR_TTY
+    else:
+        from ctypes import POINTER, WINFUNCTYPE, WinError, windll
+        from ctypes.wintypes import BOOL, DWORD, HANDLE
+
+        STD_HANDLE = -11 if stdout else -12
+        ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
+
+        def err_handler(result, func, args):
+            if not result:
+                raise WinError()
+            return args
+
+        GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32), ((1, "nStdHandle"),))
+        GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
+            ("GetConsoleMode", windll.kernel32),
+            ((1, "hConsoleHandle"), (2, "lpMode")),
+        )
+        GetConsoleMode.errcheck = err_handler
+        SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(
+            ("SetConsoleMode", windll.kernel32),
+            ((1, "hConsoleHandle"), (1, "dwMode")),
+        )
+        SetConsoleMode.errcheck = err_handler
+
+        try:
+            handle = GetStdHandle(STD_HANDLE)
+            flags = GetConsoleMode(handle)
+            SetConsoleMode(handle, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+            return True
+        except OSError:
+            return False
+
+
+STDOUT_COLOR: Final[bool] = _color_supported(True)
+STDERR_COLOR: Final[bool] = _color_supported(False)
+_stdout_override: bool = STDOUT_COLOR
+_stderr_override: bool = STDERR_COLOR
+
+
+def toggle_color(stdout: bool, value: bool | None = None) -> None:
+    """
+    Explicitly toggle color codes, regardless of support.
+
+    - `stdout`: A boolean to choose the output stream. `True` for stdout, `False` for stderr.
+    - `value`: An optional boolean to explicitly set the color state instead of toggling.
+    """
+    if stdout:
+        global _stdout_override
+        _stdout_override = value if value is not None else not _stdout_override
+    else:
+        global _stderr_override
+        _stderr_override = value if value is not None else not _stderr_override
+
+
+class Ansi(Enum):
+    """
+    Enum class for adding ansi codepoints directly into strings. Automatically converts values to
+    strings representing their internal value.
+    """
+
+    RESET = "\x1b[0m"
+
+    BOLD = "\x1b[1m"
+    DIM = "\x1b[2m"
+    ITALIC = "\x1b[3m"
+    UNDERLINE = "\x1b[4m"
+    STRIKETHROUGH = "\x1b[9m"
+    REGULAR = "\x1b[22;23;24;29m"
+
+    BLACK = "\x1b[30m"
+    RED = "\x1b[31m"
+    GREEN = "\x1b[32m"
+    YELLOW = "\x1b[33m"
+    BLUE = "\x1b[34m"
+    MAGENTA = "\x1b[35m"
+    CYAN = "\x1b[36m"
+    WHITE = "\x1b[37m"
+    GRAY = "\x1b[90m"
+
+    def __str__(self) -> str:
+        return self.value
+
+
+def print_info(*values: object) -> None:
+    """Prints a informational message with formatting."""
+    if _stdout_override:
+        print(f"{Ansi.GRAY}{Ansi.BOLD}INFO:{Ansi.REGULAR}", *values, Ansi.RESET)
+    else:
+        print(*values)
+
+
+def print_warning(*values: object) -> None:
+    """Prints a warning message with formatting."""
+    if _stderr_override:
+        print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
+    else:
+        print(*values, file=sys.stderr)
+
+
+def print_error(*values: object) -> None:
+    """Prints an error message with formatting."""
+    if _stderr_override:
+        print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR}", *values, Ansi.RESET, file=sys.stderr)
+    else:
+        print(*values, file=sys.stderr)

+ 2 - 27
modules/text_server_adv/gdextension_build/SConstruct

@@ -1,14 +1,8 @@
 #!/usr/bin/env python
-
-import atexit
-import time
-from typing import TYPE_CHECKING
+# ruff: noqa: F821
 
 import methods
 
-if TYPE_CHECKING:
-    from misc.utility.scons_hints import *
-
 # For the reference:
 # - CCFLAGS are compilation flags shared between C and C++
 # - CFLAGS are for C-specific compilation flags
@@ -17,8 +11,6 @@ if TYPE_CHECKING:
 # - CPPDEFINES are for pre-processor defines
 # - LINKFLAGS are for linking flags
 
-time_at_start = time.time()
-
 env = SConscript("./godot-cpp/SConstruct")
 env.__class__.disable_warnings = methods.disable_warnings
 
@@ -33,9 +25,6 @@ opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", Fa
 
 opts.Update(env)
 
-if not env["verbose"]:
-    methods.no_verbose(env)
-
 if env["platform"] == "windows" and not env["use_mingw"]:
     env.AppendUnique(CCFLAGS=["/utf-8"])  # Force to use Unicode encoding.
 
@@ -767,18 +756,4 @@ else:
 
 Default(library)
 
-
-def print_elapsed_time():
-    elapsed_time_sec = round(time.time() - time_at_start, 2)
-    time_centiseconds = round((elapsed_time_sec % 1) * 100)
-    print(
-        "{}[Time elapsed: {}.{:02}]{}".format(
-            methods.Ansi.GRAY,
-            time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
-            time_centiseconds,
-            methods.Ansi.RESET,
-        )
-    )
-
-
-atexit.register(print_elapsed_time)
+methods.prepare_timer()

+ 15 - 38
modules/text_server_adv/gdextension_build/methods.py

@@ -1,41 +1,3 @@
-import os
-import sys
-
-sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../"))
-
-from methods import Ansi
-
-
-def no_verbose(env):
-    colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
-
-    # There is a space before "..." to ensure that source file names can be
-    # Ctrl + clicked in the VS Code terminal.
-    compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
-    java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
-    compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(*colors)
-    link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(*colors)
-    link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(*colors)
-    ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(*colors)
-    link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors)
-    java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors)
-    compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors)
-    generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors)
-
-    env["CXXCOMSTR"] = compile_source_message
-    env["CCCOMSTR"] = compile_source_message
-    env["SHCCCOMSTR"] = compile_shared_source_message
-    env["SHCXXCOMSTR"] = compile_shared_source_message
-    env["ARCOMSTR"] = link_library_message
-    env["RANLIBCOMSTR"] = ranlib_library_message
-    env["SHLINKCOMSTR"] = link_shared_library_message
-    env["LINKCOMSTR"] = link_program_message
-    env["JARCOMSTR"] = java_library_message
-    env["JAVACCOMSTR"] = java_compile_source_message
-    env["RCCOMSTR"] = compiled_resource_message
-    env["GENCOMSTR"] = generated_file_message
-
-
 def disable_warnings(self):
     # 'self' is the environment
     if self["platform"] == "windows" and not self["use_mingw"]:
@@ -50,6 +12,19 @@ def disable_warnings(self):
         self.AppendUnique(CCFLAGS=["-w"])
 
 
+def prepare_timer():
+    import atexit
+    import time
+
+    def print_elapsed_time(time_at_start: float):
+        time_elapsed = time.time() - time_at_start
+        time_formatted = time.strftime("%H:%M:%S", time.gmtime(time_elapsed))
+        time_centiseconds = round((time_elapsed % 1) * 100)
+        print(f"[Time elapsed: {time_formatted}.{time_centiseconds}]")
+
+    atexit.register(print_elapsed_time, time.time())
+
+
 def make_icu_data(target, source, env):
     dst = target[0].srcnode().abspath
     with open(dst, "w", encoding="utf-8", newline="\n") as g:
@@ -75,6 +50,8 @@ def make_icu_data(target, source, env):
 
 
 def write_macos_plist(target, binary_name, identifier, name):
+    import os
+
     os.makedirs(f"{target}/Resource/", exist_ok=True)
     with open(f"{target}/Resource/Info.plist", "w", encoding="utf-8", newline="\n") as f:
         f.write(f"""\

+ 2 - 27
modules/text_server_fb/gdextension_build/SConstruct

@@ -1,14 +1,8 @@
 #!/usr/bin/env python
-
-import atexit
-import time
-from typing import TYPE_CHECKING
+# ruff: noqa: F821
 
 import methods
 
-if TYPE_CHECKING:
-    from misc.utility.scons_hints import *
-
 # For the reference:
 # - CCFLAGS are compilation flags shared between C and C++
 # - CFLAGS are for C-specific compilation flags
@@ -17,8 +11,6 @@ if TYPE_CHECKING:
 # - CPPDEFINES are for pre-processor defines
 # - LINKFLAGS are for linking flags
 
-time_at_start = time.time()
-
 env = SConscript("./godot-cpp/SConstruct")
 env.__class__.disable_warnings = methods.disable_warnings
 
@@ -31,9 +23,6 @@ opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", Fa
 
 opts.Update(env)
 
-if not env["verbose"]:
-    methods.no_verbose(env)
-
 # ThorVG
 if env["thorvg_enabled"] and env["freetype_enabled"]:
     env_tvg = env.Clone()
@@ -313,18 +302,4 @@ else:
 
 Default(library)
 
-
-def print_elapsed_time():
-    elapsed_time_sec = round(time.time() - time_at_start, 2)
-    time_centiseconds = round((elapsed_time_sec % 1) * 100)
-    print(
-        "{}[Time elapsed: {}.{:02}]{}".format(
-            methods.Ansi.GRAY,
-            time.strftime("%H:%M:%S", time.gmtime(elapsed_time_sec)),
-            time_centiseconds,
-            methods.Ansi.RESET,
-        )
-    )
-
-
-atexit.register(print_elapsed_time)
+methods.prepare_timer()

+ 11 - 58
modules/text_server_fb/gdextension_build/methods.py

@@ -1,41 +1,3 @@
-import os
-import sys
-
-sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../../"))
-
-from methods import Ansi
-
-
-def no_verbose(env):
-    colors = [Ansi.BLUE, Ansi.BOLD, Ansi.REGULAR, Ansi.RESET]
-
-    # There is a space before "..." to ensure that source file names can be
-    # Ctrl + clicked in the VS Code terminal.
-    compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
-    java_compile_source_message = "{}Compiling {}$SOURCE{} ...{}".format(*colors)
-    compile_shared_source_message = "{}Compiling shared {}$SOURCE{} ...{}".format(*colors)
-    link_program_message = "{}Linking Program {}$TARGET{} ...{}".format(*colors)
-    link_library_message = "{}Linking Static Library {}$TARGET{} ...{}".format(*colors)
-    ranlib_library_message = "{}Ranlib Library {}$TARGET{} ...{}".format(*colors)
-    link_shared_library_message = "{}Linking Shared Library {}$TARGET{} ...{}".format(*colors)
-    java_library_message = "{}Creating Java Archive {}$TARGET{} ...{}".format(*colors)
-    compiled_resource_message = "{}Creating Compiled Resource {}$TARGET{} ...{}".format(*colors)
-    generated_file_message = "{}Generating {}$TARGET{} ...{}".format(*colors)
-
-    env["CXXCOMSTR"] = compile_source_message
-    env["CCCOMSTR"] = compile_source_message
-    env["SHCCCOMSTR"] = compile_shared_source_message
-    env["SHCXXCOMSTR"] = compile_shared_source_message
-    env["ARCOMSTR"] = link_library_message
-    env["RANLIBCOMSTR"] = ranlib_library_message
-    env["SHLINKCOMSTR"] = link_shared_library_message
-    env["LINKCOMSTR"] = link_program_message
-    env["JARCOMSTR"] = java_library_message
-    env["JAVACCOMSTR"] = java_compile_source_message
-    env["RCCOMSTR"] = compiled_resource_message
-    env["GENCOMSTR"] = generated_file_message
-
-
 def disable_warnings(self):
     # 'self' is the environment
     if self["platform"] == "windows" and not self["use_mingw"]:
@@ -50,31 +12,22 @@ def disable_warnings(self):
         self.AppendUnique(CCFLAGS=["-w"])
 
 
-def make_icu_data(target, source, env):
-    dst = target[0].srcnode().abspath
-    with open(dst, "w", encoding="utf-8", newline="\n") as g:
-        g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
-        g.write("/* (C) 2016 and later: Unicode, Inc. and others. */\n")
-        g.write("/* License & terms of use: https://www.unicode.org/copyright.html */\n")
-        g.write("#ifndef _ICU_DATA_H\n")
-        g.write("#define _ICU_DATA_H\n")
-        g.write('#include "unicode/utypes.h"\n')
-        g.write('#include "unicode/udata.h"\n')
-        g.write('#include "unicode/uversion.h"\n')
+def prepare_timer():
+    import atexit
+    import time
 
-        with open(source[0].srcnode().abspath, "rb") as f:
-            buf = f.read()
+    def print_elapsed_time(time_at_start: float):
+        time_elapsed = time.time() - time_at_start
+        time_formatted = time.strftime("%H:%M:%S", time.gmtime(time_elapsed))
+        time_centiseconds = round((time_elapsed % 1) * 100)
+        print(f"[Time elapsed: {time_formatted}.{time_centiseconds}]")
 
-        g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n")
-        g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n')
-        for i in range(len(buf)):
-            g.write("\t" + str(buf[i]) + ",\n")
-
-        g.write("};\n")
-        g.write("#endif")
+    atexit.register(print_elapsed_time, time.time())
 
 
 def write_macos_plist(target, binary_name, identifier, name):
+    import os
+
     os.makedirs(f"{target}/Resource/", exist_ok=True)
     with open(f"{target}/Resource/Info.plist", "w", encoding="utf-8", newline="\n") as f:
         f.write(f"""\

+ 0 - 3
platform/windows/detect.py

@@ -812,9 +812,6 @@ def configure_mingw(env: "SConsEnvironment"):
         env.Append(CCFLAGS=san_flags)
         env.Append(LINKFLAGS=san_flags)
 
-    if env["use_llvm"] and os.name == "nt" and methods._can_color:
-        env.Append(CCFLAGS=["$(-fansi-escape-codes$)", "$(-fcolor-diagnostics$)"])
-
     if get_is_ar_thin_supported(env):
         env.Append(ARFLAGS=["--thin"])