Fixed ninja binary location logic to use ninja.BIN_DIR. Previous logic no longer...
[scons.git] / SCons / Warnings.py
blobb9f9cc16f43c10b980244d95c04b195de2db17b7
1 # MIT License
3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 """The SCons Warnings framework.
26 Enables issuing warnings in situations where it is useful to alert
27 the user of a condition that does not warrant raising an exception
28 that could terminate the program.
30 A new warning class should inherit (perhaps indirectly) from one of
31 two base classes: :exc:`SConsWarning` or :exc:`WarningOnByDefault`,
32 which are the same except warnings derived from the latter will start
33 out in an enabled state. Enabled warnings cause a message to be
34 printed when called, disabled warnings are silent.
36 There is also a hierarchy for indicating deprecations and future
37 changes: for these, derive from :exc:`DeprecatedWarning`,
38 :exc:`MandatoryDeprecatedWarning`, :exc:`FutureDeprecatedWarning`
39 or :exc:`FutureReservedVariableWarning`.
41 Whether or not to display warnings, beyond those that are on by
42 default, is controlled through the command line (``--warn``) or
43 through ``SetOption('warn')``. The names used there use a different
44 naming style than the warning class names. :func:`process_warn_strings`
45 converts the names before enabling/disabling.
47 The behavior of issuing only a message (for "enabled" warnings) can
48 be toggled to raising an exception instead by calling the
49 :func:`warningAsException` function.
51 For new/removed warnings, the manpage needs to be kept in sync.
52 Any warning class defined here is accepted, but we don't want to make
53 people have to dig around to find the names. Warnings do not have to
54 be defined in this file, though it is preferred: those defined elsewhere
55 cannot use the enable/disable functionality unless they monkeypatch the
56 warning into this module's namespace.
58 You issue a warning, either in SCons code or in a build project's
59 SConscripts, by calling the :func:`warn` function defined in this module.
60 Raising directly with an instance of a warning class bypasses the
61 framework and it will behave like an ordinary exception.
62 """
64 from __future__ import annotations
66 import sys
67 from typing import Callable, Sequence
69 import SCons.Errors
71 # _enabled is a list of 2-tuples with a warning class object and a
72 # boolean (True if that warning is enabled). Initialized in SCons/Main.py.
73 _enabled = []
75 # If False, just emit the msg for an enabled warning; else raise exception
76 _warningAsException: bool = False
78 # Function to emit the warning. Initialized by SCons/Main.py for regular use;
79 # the unit test will set to a capturing version for testing.
80 _warningOut: Callable | None = None
83 class SConsWarning(SCons.Errors.UserError):
84 """Base class for all SCons warnings."""
86 class WarningOnByDefault(SConsWarning):
87 """Base class for SCons warnings that are enabled by default."""
89 SConsWarningOnByDefault = WarningOnByDefault # transition to new name
92 class LinkWarning(WarningOnByDefault):
93 """Base class for linker warnings."""
95 # NOTE: If you add a new warning class here, add it to the man page, too!
97 # General warnings
99 class CacheVersionWarning(WarningOnByDefault):
100 """The derived-file cache directory has an out of date config."""
102 class CacheWriteErrorWarning(SConsWarning):
103 """Problems writing a derived file to the cache."""
105 class CacheCleanupErrorWarning(SConsWarning):
106 """Problems removing retrieved target prior to rebuilding."""
108 class CorruptSConsignWarning(WarningOnByDefault):
109 """Problems decoding the contents of the sconsign database."""
111 class DependencyWarning(SConsWarning):
112 """A scanner identified a dependency but did not add it."""
114 class DevelopmentVersionWarning(WarningOnByDefault):
115 """Use of a deprecated feature."""
117 class DuplicateEnvironmentWarning(WarningOnByDefault):
118 """A target appears in more than one consenv with identical actions.
120 A duplicate target with different rules cannot be built;
121 with the same rule it can, but this could indicate a problem in
122 the build configuration.
125 class FortranCxxMixWarning(LinkWarning):
126 """Fortran and C++ objects appear together in a link line.
128 Some compilers support this, others do not.
131 class FutureReservedVariableWarning(WarningOnByDefault):
132 """Setting a variable marked to become reserved in a future release."""
134 class MisleadingKeywordsWarning(WarningOnByDefault):
135 """Use of possibly misspelled kwargs in Builder calls."""
137 class MissingSConscriptWarning(WarningOnByDefault):
138 """The script specified in an SConscript() call was not found.
140 TODO: this is now an error, so no need for a warning. Left in for
141 a while in case anyone is using, remove eventually.
143 Manpage entry removed in 4.6.0.
146 class NoObjectCountWarning(WarningOnByDefault):
147 """Object counting (debug mode) could not be enabled."""
149 class NoParallelSupportWarning(WarningOnByDefault):
150 """Fell back to single-threaded build, as no thread support found."""
152 class ReservedVariableWarning(WarningOnByDefault):
153 """Attempt to set reserved construction variable names."""
155 class StackSizeWarning(WarningOnByDefault):
156 """Requested thread stack size could not be set."""
158 class TargetNotBuiltWarning(SConsWarning): # TODO: should go to OnByDefault
159 """A target build indicated success but the file is not found."""
161 class VisualCMissingWarning(WarningOnByDefault):
162 """Requested MSVC version not found and policy is to not fail."""
164 class VisualVersionMismatch(WarningOnByDefault):
165 """``MSVC_VERSION`` and ``MSVS_VERSION`` do not match.
167 Note ``MSVS_VERSION`` is deprecated, use ``MSVC_VERSION``.
170 class VisualStudioMissingWarning(SConsWarning): # TODO: unused
171 pass
174 # Deprecation warnings
176 class FutureDeprecatedWarning(SConsWarning):
177 """Base class for features that will become deprecated in a future release."""
179 class DeprecatedWarning(SConsWarning):
180 """Base class for deprecated features, will be removed in future."""
182 class MandatoryDeprecatedWarning(DeprecatedWarning):
183 """Base class for deprecated features where warning cannot be disabled."""
186 # Special case; base always stays DeprecatedWarning
187 class PythonVersionWarning(DeprecatedWarning):
188 """SCons was run with a deprecated Python version."""
190 class DeprecatedOptionsWarning(MandatoryDeprecatedWarning):
191 """Options that are deprecated."""
193 class DeprecatedDebugOptionsWarning(MandatoryDeprecatedWarning):
194 """Option-arguments to --debug that are deprecated."""
196 class ToolQtDeprecatedWarning(DeprecatedWarning): # TODO: unused
197 pass
200 def suppressWarningClass(clazz) -> None:
201 """Suppresses all warnings of type *clazz* or derived from *clazz*."""
202 _enabled.insert(0, (clazz, False))
204 def enableWarningClass(clazz) -> None:
205 """Enables all warnings of type *clazz* or derived from *clazz*."""
206 _enabled.insert(0, (clazz, True))
208 def warningAsException(flag: bool = True) -> bool:
209 """Sets global :data:`_warningAsExeption` flag.
211 If true, any enabled warning will cause an exception to be raised.
213 Args:
214 flag: new value for warnings-as-exceptions.
216 Returns:
217 The previous value.
219 global _warningAsException # pylint: disable=global-statement
220 old = _warningAsException
221 _warningAsException = flag
222 return old
224 def warn(clazz, *args) -> None:
225 """Issue a warning, accounting for SCons rules.
227 Check if warnings for this class are enabled. If warnings are treated
228 as exceptions, raise exception. Use the global warning emitter
229 :data:`_warningOut`, which allows selecting different ways of
230 presenting a traceback (see Script/Main.py).
232 warning = clazz(args)
233 for cls, flag in _enabled:
234 if isinstance(warning, cls):
235 if flag:
236 if _warningAsException:
237 raise warning
239 if _warningOut is not None:
240 _warningOut(warning)
241 break
243 def process_warn_strings(arguments: Sequence[str]) -> None:
244 """Process requests to enable/disable warnings.
246 The requests come from the option-argument string passed to the
247 ``--warn`` command line option or as the value passed to the
248 ``SetOption`` function with a first argument of ``warn``;
251 The arguments are expected to be as documented in the SCons manual
252 page for the ``--warn`` option, in the style ``some-type``,
253 which is converted here to a camel-case name like ``SomeTypeWarning``,
254 to try to match the warning classes defined here, which are then
255 passed to :func:`enableWarningClass` or :func:`suppressWarningClass`.
257 For example, a string``"deprecated"`` enables the
258 :exc:`DeprecatedWarning` class, while a string``"no-dependency"``
259 disables the :exc:`DependencyWarning` class.
261 As a special case, the string ``"all"`` disables all warnings and
262 a the string ``"no-all"`` disables all warnings.
264 def _classmunge(s: str) -> str:
265 """Convert a warning argument to SConsCase.
267 The result is CamelCase, except "Scons" is changed to "SCons"
269 s = s.replace("-", " ").title().replace(" ", "")
270 return s.replace("Scons", "SCons")
272 for arg in arguments:
273 enable = True
274 if arg.startswith("no-") and arg not in (
275 "no-object-count",
276 "no-parallel-support",
278 enable = False
279 arg = arg[len("no-") :]
280 if arg == 'all':
281 class_name = "SConsWarning"
282 else:
283 class_name = _classmunge(arg) + 'Warning'
284 try:
285 clazz = globals()[class_name]
286 except KeyError:
287 sys.stderr.write(f"No warning type: {arg!r}\n")
288 else:
289 if enable:
290 enableWarningClass(clazz)
291 elif issubclass(clazz, MandatoryDeprecatedWarning):
292 sys.stderr.write(f"Can not disable mandataory warning: {arg!r}\n")
293 else:
294 suppressWarningClass(clazz)
296 # Local Variables:
297 # tab-width:4
298 # indent-tabs-mode:nil
299 # End:
300 # vim: set expandtab tabstop=4 shiftwidth=4: