11import os
2+ import re
23import subprocess
34import sys
45from SCons .Script import ARGUMENTS
910# Helper methods
1011
1112
13+ def get_compiler_version (env ):
14+ """
15+ Returns an array of version numbers as ints: [major, minor, patch].
16+ The return array should have at least two values (major, minor).
17+ """
18+ if not env .get ("is_msvc" , False ):
19+ # Not using -dumpversion as some GCC distros only return major, and
20+ # Clang used to return hardcoded 4.2.1: # https://reviews.llvm.org/D56803
21+ try :
22+ version = subprocess .check_output ([env .subst (env ["CXX" ]), "--version" ]).strip ().decode ("utf-8" )
23+ except (subprocess .CalledProcessError , OSError ):
24+ print ("Couldn't parse CXX environment variable to infer compiler version." )
25+ return None
26+ else : # TODO: Implement for MSVC
27+ return None
28+ match = re .search (
29+ "(?:(?<=version )|(?<=\) )|(?<=^))"
30+ "(?P<major>\d+)"
31+ "(?:\.(?P<minor>\d*))?"
32+ "(?:\.(?P<patch>\d*))?"
33+ "(?:-(?P<metadata1>[0-9a-zA-Z-]*))?"
34+ "(?:\+(?P<metadata2>[0-9a-zA-Z-]*))?"
35+ "(?: (?P<date>[0-9]{8}|[0-9]{6})(?![0-9a-zA-Z]))?" ,
36+ version ,
37+ )
38+ if match is not None :
39+ return match .groupdict ()
40+ else :
41+ return None
42+
43+
1244def get_cmdline_bool (option , default ):
1345 """We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
1446 and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
@@ -20,6 +52,14 @@ def get_cmdline_bool(option, default):
2052 return default
2153
2254
55+ def using_gcc (env ):
56+ return "gcc" in os .path .basename (env ["CC" ])
57+
58+
59+ def using_emcc (env ):
60+ return "emcc" in os .path .basename (env ["CC" ])
61+
62+
2363def using_clang (env ):
2464 return "clang" in os .path .basename (env ["CC" ])
2565
@@ -49,6 +89,8 @@ def options(opts):
4989 )
5090 opts .Add (BoolVariable ("debug_symbols" , "Build with debugging symbols" , True ))
5191 opts .Add (BoolVariable ("dev_build" , "Developer build with dev-only debugging code (DEV_ENABLED)" , False ))
92+ opts .Add (EnumVariable ("warnings" , "Level of compilation warnings" , "all" , ("extra" , "all" , "moderate" , "no" )))
93+ opts .Add (BoolVariable ("werror" , "Treat compiler warnings as errors" , False ))
5294
5395
5496def exists (env ):
@@ -115,6 +157,37 @@ def generate(env):
115157 env .Append (LINKFLAGS = ["/OPT:REF" ])
116158 elif env ["optimize" ] == "debug" or env ["optimize" ] == "none" :
117159 env .Append (CCFLAGS = ["/Od" ])
160+
161+ # Warnings
162+ if env ["warnings" ] == "no" :
163+ env .Append (CCFLAGS = ["/w" ])
164+ else :
165+ if env ["warnings" ] == "extra" :
166+ env .Append (CCFLAGS = ["/W4" ])
167+ elif env ["warnings" ] == "all" :
168+ env .Append (CCFLAGS = ["/W3" ])
169+ elif env ["warnings" ] == "moderate" :
170+ env .Append (CCFLAGS = ["/W2" ])
171+ # Disable warnings which we don't plan to fix.
172+
173+ env .Append (
174+ CCFLAGS = [
175+ "/wd4100" , # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
176+ "/wd4127" , # C4127 (conditional expression is constant)
177+ "/wd4201" , # C4201 (non-standard nameless struct/union): Only relevant for C89.
178+ "/wd4244" , # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
179+ "/wd4245" ,
180+ "/wd4267" ,
181+ "/wd4305" , # C4305 (truncation): double to float or real_t, too hard to avoid.
182+ "/wd4514" , # C4514 (unreferenced inline function has been removed)
183+ "/wd4714" , # C4714 (function marked as __forceinline not inlined)
184+ "/wd4820" , # C4820 (padding added after construct)
185+ ]
186+ )
187+
188+ if env ["werror" ]:
189+ env .Append (CCFLAGS = ["/WX" ])
190+
118191 else :
119192 if env ["debug_symbols" ]:
120193 # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
@@ -142,3 +215,64 @@ def generate(env):
142215 env .Append (CCFLAGS = ["-Og" ])
143216 elif env ["optimize" ] == "none" :
144217 env .Append (CCFLAGS = ["-O0" ])
218+
219+ # Warnings
220+ cc_version = get_compiler_version (env ) or {
221+ "major" : None ,
222+ "minor" : None ,
223+ "patch" : None ,
224+ "metadata1" : None ,
225+ "metadata2" : None ,
226+ "date" : None ,
227+ }
228+ cc_version_major = int (cc_version ["major" ] or - 1 )
229+ cc_version_minor = int (cc_version ["minor" ] or - 1 )
230+
231+ common_warnings = []
232+
233+ if using_gcc (env ):
234+ common_warnings += ["-Wshadow-local" , "-Wno-misleading-indentation" ]
235+ if cc_version_major == 7 : # Bogus warning fixed in 8+.
236+ common_warnings += ["-Wno-strict-overflow" ]
237+ if cc_version_major < 11 :
238+ # Regression in GCC 9/10, spams so much in our variadic templates
239+ # that we need to outright disable it.
240+ common_warnings += ["-Wno-type-limits" ]
241+ if cc_version_major >= 12 : # False positives in our error macros, see GH-58747.
242+ common_warnings += ["-Wno-return-type" ]
243+ elif using_clang (env ) or using_emcc (env ):
244+ # We often implement `operator<` for structs of pointers as a requirement
245+ # for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
246+ common_warnings += ["-Wno-ordered-compare-function-pointers" ]
247+
248+ if env ["warnings" ] == "extra" :
249+ env .Append (CCFLAGS = ["-Wall" , "-Wextra" , "-Wwrite-strings" , "-Wno-unused-parameter" ] + common_warnings )
250+ env .Append (CXXFLAGS = ["-Wctor-dtor-privacy" , "-Wnon-virtual-dtor" ])
251+ if using_gcc (env ):
252+ env .Append (
253+ CCFLAGS = [
254+ "-Walloc-zero" ,
255+ "-Wduplicated-branches" ,
256+ "-Wduplicated-cond" ,
257+ "-Wstringop-overflow=4" ,
258+ ]
259+ )
260+ env .Append (CXXFLAGS = ["-Wplacement-new=1" ])
261+ # Need to fix a warning with AudioServer lambdas before enabling.
262+ # if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
263+ # env.Append(CXXFLAGS=["-Wnoexcept"])
264+ if cc_version_major >= 9 :
265+ env .Append (CCFLAGS = ["-Wattribute-alias=2" ])
266+ if cc_version_major >= 11 : # Broke on MethodBind templates before GCC 11.
267+ env .Append (CCFLAGS = ["-Wlogical-op" ])
268+ elif using_clang (env ) or using_emcc (env ):
269+ env .Append (CCFLAGS = ["-Wimplicit-fallthrough" ])
270+ elif env ["warnings" ] == "all" :
271+ env .Append (CCFLAGS = ["-Wall" ] + common_warnings )
272+ elif env ["warnings" ] == "moderate" :
273+ env .Append (CCFLAGS = ["-Wall" , "-Wno-unused" ] + common_warnings )
274+ else : # 'no'
275+ env .Append (CCFLAGS = ["-w" ])
276+
277+ if env ["werror" ]:
278+ env .Append (CCFLAGS = ["-Werror" ])
0 commit comments