Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works.

4.0.16 (in development)
-----------------------
- For windows users, colored console output for error messages and logging now
requires Windows 10 or above. (#25502)
- A warning was added about usage of embind without C++17 or above. (#25424)
- The minimum supported versions of Node, Chrome and Firefox were bumped
enabling the removal of the `globalThis` polyfill and universally enabling
Expand Down
15 changes: 3 additions & 12 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -11607,21 +11607,12 @@ def test_color_diagnostics_disable(self, flag):
})
def test_color_diagnostics_force(self, flag):
create_file('src.c', 'int main() {')
# -fansi-escape-codes is needed here to make this test work on windows, which doesn't
# use ansi codes by default
output = self.expect_fail([EMCC, '-fansi-escape-codes', flag, 'src.c'])
# -fansi-escape-codes is needed on windows in order to get clang to emit ANSI colors
output = self.expect_fail([EMCC, flag, '-fansi-escape-codes', 'src.c'])
self.assertIn("\x1b[1msrc.c:1:13: \x1b[0m\x1b[0;1;31merror: \x1b[0m\x1b[1mexpected '}'\x1b[0m", output)
# Verify that emcc errors show up as red and bold
# Verify that emcc errors show up as red and bold from emcc
self.assertIn('emcc: \x1b[31m\x1b[1m', output)

if WINDOWS:
# Also test without -fansi-escape-codes on windows.
# In those mode the code will use kernel calls such as SetConsoleTextAttribute to
# change the output color. We cannot detect this in the output, but we can at least
# get coverage of the code path in the diagnositics.py.
output = self.expect_fail([EMCC, flag, 'src.c'])
self.assertNotIn('\x1b', output)

def test_sanitizer_color(self):
create_file('src.c', '''
#include <emscripten.h>
Expand Down
2 changes: 0 additions & 2 deletions tools/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,6 @@ def consume_arg_file():
diagnostics.color_enabled = True
elif arg in ('-fno-color-diagnostics', '-fdiagnostics-color=never'):
diagnostics.color_enabled = False
elif arg == '-fansi-escape-codes':
diagnostics.force_ansi = True
elif arg == '-fno-exceptions':
settings.DISABLE_EXCEPTION_CATCHING = 1
settings.DISABLE_EXCEPTION_THROWING = 1
Expand Down
98 changes: 16 additions & 82 deletions tools/colored_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,88 +11,25 @@
import logging


def add_coloring_to_emit_windows(fn):
def ansi_color_available():
if not sys.platform.startswith('win'):
return sys.stderr.isatty()

# Constants from the Windows API
STD_OUTPUT_HANDLE = -11
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004

def _get_color():
SHORT = ctypes.c_short
WORD = ctypes.c_ushort

class COORD(ctypes.Structure):
_fields_ = [
("X", SHORT),
("Y", SHORT)]

class SMALL_RECT(ctypes.Structure):
_fields_ = [
("Left", SHORT),
("Top", SHORT),
("Right", SHORT),
("Bottom", SHORT)]

class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", WORD),
("srWindow", SMALL_RECT),
("dwMaximumWindowSize", COORD)]
kernel32 = ctypes.windll.kernel32
stdout_handle = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)

hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
csbi = CONSOLE_SCREEN_BUFFER_INFO()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(hdl, ctypes.byref(csbi))
return csbi.wAttributes
# Get the current console mode
console_mode = ctypes.c_uint()
if not kernel32.GetConsoleMode(stdout_handle, ctypes.byref(console_mode)):
# Handle error if GetConsoleMode fails
return False

def _set_color(code):
hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, code)

def new(*args):
# wincon.h
FOREGROUND_BLACK = 0x0000 # noqa
FOREGROUND_BLUE = 0x0001 # noqa
FOREGROUND_GREEN = 0x0002 # noqa
FOREGROUND_CYAN = 0x0003 # noqa
FOREGROUND_RED = 0x0004 # noqa
FOREGROUND_MAGENTA = 0x0005 # noqa
FOREGROUND_YELLOW = 0x0006 # noqa
FOREGROUND_GREY = 0x0007 # noqa
FOREGROUND_INTENSITY = 0x0008 # foreground color is intensified.

FOREGROUND_WHITE = FOREGROUND_BLUE|FOREGROUND_GREEN |FOREGROUND_RED # noqa

BACKGROUND_BLACK = 0x0000 # noqa
BACKGROUND_BLUE = 0x0010 # noqa
BACKGROUND_GREEN = 0x0020 # noqa
BACKGROUND_CYAN = 0x0030 # noqa
BACKGROUND_RED = 0x0040 # noqa
BACKGROUND_MAGENTA = 0x0050 # noqa
BACKGROUND_YELLOW = 0x0060 # noqa
BACKGROUND_GREY = 0x0070 # noqa
BACKGROUND_INTENSITY = 0x0080 # background color is intensified.
levelno = args[1].levelno
if (levelno >= 50):
color = BACKGROUND_YELLOW | FOREGROUND_RED | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY
elif (levelno >= 40):
color = FOREGROUND_RED | FOREGROUND_INTENSITY
elif (levelno >= 30):
color = FOREGROUND_YELLOW | FOREGROUND_INTENSITY
elif (levelno >= 20):
color = FOREGROUND_GREEN
elif (levelno >= 10):
color = FOREGROUND_MAGENTA
else:
color = FOREGROUND_WHITE

old_color = _get_color()
_set_color(color)
ret = fn(*args)
_set_color(old_color)
return ret

new.orig_func = fn
return new
# Check if the flag is set in the current console mode
return (console_mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0


def add_coloring_to_emit_ansi(fn):
Expand All @@ -117,11 +54,8 @@ def new(*args):


def enable():
if sys.stderr.isatty():
if sys.platform.startswith('win'):
logging.StreamHandler.emit = add_coloring_to_emit_windows(logging.StreamHandler.emit)
else:
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)
if ansi_color_available():
logging.StreamHandler.emit = add_coloring_to_emit_ansi(logging.StreamHandler.emit)


def disable():
Expand Down
92 changes: 6 additions & 86 deletions tools/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@
"""Simple color-enabled diagnositics reporting functions.
"""

import ctypes
import logging
import os
import sys
from typing import Dict

WINDOWS = sys.platform.startswith('win')
from . import colored_logger

color_enabled = colored_logger.ansi_color_available()
logger = logging.getLogger('diagnostics')
color_enabled = sys.stderr.isatty()
tool_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
force_ansi = False

# diagnostic levels
WARN = 1
ERROR = 2

# available colors
# available (ANSI) colors
RED = 1
GREEN = 2
YELLOW = 3
Expand All @@ -43,94 +41,19 @@
ERROR: 'error: ',
}

# Constants from the Windows API
STD_OUTPUT_HANDLE = -11


def output_color_windows(color):
assert not force_ansi
# TODO(sbc): This code is duplicated in colored_logger.py. Refactor.
# wincon.h
FOREGROUND_BLACK = 0x0000 # noqa
FOREGROUND_BLUE = 0x0001 # noqa
FOREGROUND_GREEN = 0x0002 # noqa
FOREGROUND_CYAN = 0x0003 # noqa
FOREGROUND_RED = 0x0004 # noqa
FOREGROUND_MAGENTA = 0x0005 # noqa
FOREGROUND_YELLOW = 0x0006 # noqa
FOREGROUND_GREY = 0x0007 # noqa

color_map = {
RED: FOREGROUND_RED,
GREEN: FOREGROUND_GREEN,
YELLOW: FOREGROUND_YELLOW,
BLUE: FOREGROUND_BLUE,
MAGENTA: FOREGROUND_MAGENTA,
CYAN: FOREGROUND_CYAN,
WHITE: FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED,
}

sys.stderr.flush()
hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, color_map[color])


def get_color_windows():
assert not force_ansi
SHORT = ctypes.c_short
WORD = ctypes.c_ushort

class COORD(ctypes.Structure):
_fields_ = [
("X", SHORT),
("Y", SHORT)]

class SMALL_RECT(ctypes.Structure):
_fields_ = [
("Left", SHORT),
("Top", SHORT),
("Right", SHORT),
("Bottom", SHORT)]

class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
_fields_ = [
("dwSize", COORD),
("dwCursorPosition", COORD),
("wAttributes", WORD),
("srWindow", SMALL_RECT),
("dwMaximumWindowSize", COORD)]

hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
csbi = CONSOLE_SCREEN_BUFFER_INFO()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(hdl, ctypes.byref(csbi))
return csbi.wAttributes


def reset_color_windows():
assert not force_ansi
sys.stderr.flush()
hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, default_color)


def output_color(color):
if WINDOWS and not force_ansi:
output_color_windows(color)
return ''
assert color_enabled
return '\033[3%sm' % color


def bold():
if WINDOWS and not force_ansi:
# AFAICT there is no way to enable bold output on windows
return ''
assert color_enabled
return '\033[1m'


def reset_color():
if WINDOWS and not force_ansi:
reset_color_windows()
return ''
assert color_enabled
return '\033[0m'


Expand Down Expand Up @@ -260,7 +183,4 @@ def capture_warnings(argv):
return manager.capture_warnings(argv)


if WINDOWS:
default_color = get_color_windows()

manager = WarningManager()