Skip to content

Commit 53b546e

Browse files
authored
Merge pull request #1507 from Repiteo/silence-msvc
SCons: Add `silence_msvc` option for Windows
2 parents 7abe4ca + 1989b1b commit 53b546e

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

tools/windows.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,76 @@
66
from SCons.Variables import BoolVariable
77

88

9+
def silence_msvc(env):
10+
import os
11+
import re
12+
import tempfile
13+
14+
# Ensure we have a location to write captured output to, in case of false positives.
15+
capture_path = os.path.join(os.path.dirname(__file__), "..", "msvc_capture.log")
16+
with open(capture_path, "wt", encoding="utf-8"):
17+
pass
18+
19+
old_spawn = env["SPAWN"]
20+
re_redirect_stream = re.compile(r"^[12]?>")
21+
re_cl_capture = re.compile(r"^.+\.(c|cc|cpp|cxx|c[+]{2})$", re.IGNORECASE)
22+
re_link_capture = re.compile(r'\s{3}\S.+\s(?:"[^"]+.lib"|\S+.lib)\s.+\s(?:"[^"]+.exp"|\S+.exp)')
23+
24+
def spawn_capture(sh, escape, cmd, args, env):
25+
# We only care about cl/link, process everything else as normal.
26+
if args[0] not in ["cl", "link"]:
27+
return old_spawn(sh, escape, cmd, args, env)
28+
29+
# Process as normal if the user is manually rerouting output.
30+
for arg in args:
31+
if re_redirect_stream.match(arg):
32+
return old_spawn(sh, escape, cmd, args, env)
33+
34+
tmp_stdout, tmp_stdout_name = tempfile.mkstemp()
35+
os.close(tmp_stdout)
36+
args.append(f">{tmp_stdout_name}")
37+
ret = old_spawn(sh, escape, cmd, args, env)
38+
39+
try:
40+
with open(tmp_stdout_name, "r", encoding=sys.stdout.encoding, errors="replace") as tmp_stdout:
41+
lines = tmp_stdout.read().splitlines()
42+
os.remove(tmp_stdout_name)
43+
except OSError:
44+
pass
45+
46+
# Early process no lines (OSError)
47+
if not lines:
48+
return ret
49+
50+
is_cl = args[0] == "cl"
51+
content = ""
52+
caught = False
53+
for line in lines:
54+
# These conditions are far from all-encompassing, but are specialized
55+
# for what can be reasonably expected to show up in the repository.
56+
if not caught and (is_cl and re_cl_capture.match(line)) or (not is_cl and re_link_capture.match(line)):
57+
caught = True
58+
try:
59+
with open(capture_path, "a", encoding=sys.stdout.encoding) as log:
60+
log.write(line + "\n")
61+
except OSError:
62+
print(f'WARNING: Failed to log captured line: "{line}".')
63+
continue
64+
content += line + "\n"
65+
# Content remaining assumed to be an error/warning.
66+
if content:
67+
sys.stderr.write(content)
68+
69+
return ret
70+
71+
env["SPAWN"] = spawn_capture
72+
73+
974
def options(opts):
1075
opts.Add(BoolVariable("use_mingw", "Use the MinGW compiler instead of MSVC - only effective on Windows", False))
1176
opts.Add(BoolVariable("use_clang_cl", "Use the clang driver instead of MSVC - only effective on Windows", False))
1277
opts.Add(BoolVariable("use_static_cpp", "Link MinGW/MSVC C++ runtime libraries statically", True))
78+
opts.Add(BoolVariable("silence_msvc", "Silence MSVC's cl/link stdout bloat, redirecting errors to stderr.", True))
1379

1480

1581
def exists(env):
@@ -42,6 +108,9 @@ def generate(env):
42108
else:
43109
env.Append(CCFLAGS=["/MD"])
44110

111+
if env["silence_msvc"] and not env.GetOption("clean"):
112+
silence_msvc(env)
113+
45114
elif sys.platform == "win32" or sys.platform == "msys":
46115
env["use_mingw"] = True
47116
mingw.generate(env)

0 commit comments

Comments
 (0)