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.
65 from typing
import Callable
, Sequence
, Optional
69 # _enabled is a list of 2-tuples with a warning class object and a
70 # boolean (True if that warning is enabled). Initialized in SCons/Main.py.
73 # If False, just emit the msg for an enabled warning; else raise exception
74 _warningAsException
: bool = False
76 # Function to emit the warning. Initialized by SCons/Main.py for regular use;
77 # the unit test will set to a capturing version for testing.
78 _warningOut
: Optional
[Callable
] = None
81 class SConsWarning(SCons
.Errors
.UserError
):
82 """Base class for all SCons warnings."""
84 class WarningOnByDefault(SConsWarning
):
85 """Base class for SCons warnings that are enabled by default."""
87 SConsWarningOnByDefault
= WarningOnByDefault
# transition to new name
90 class LinkWarning(WarningOnByDefault
):
91 """Base class for linker warnings."""
93 # NOTE: If you add a new warning class here, add it to the man page, too!
97 class CacheVersionWarning(WarningOnByDefault
):
98 """The derived-file cache directory has an out of date config."""
100 class CacheWriteErrorWarning(SConsWarning
):
101 """Problems writing a derived file to the cache."""
103 class CacheCleanupErrorWarning(SConsWarning
):
104 """Problems removing retrieved target prior to rebuilding."""
106 class CorruptSConsignWarning(WarningOnByDefault
):
107 """Problems decoding the contents of the sconsign database."""
109 class DependencyWarning(SConsWarning
):
110 """A scanner identified a dependency but did not add it."""
112 class DevelopmentVersionWarning(WarningOnByDefault
):
113 """Use of a deprecated feature."""
115 class DuplicateEnvironmentWarning(WarningOnByDefault
):
116 """A target appears in more than one consenv with identical actions.
118 A duplicate target with different rules cannot be built;
119 with the same rule it can, but this could indicate a problem in
120 the build configuration.
123 class FortranCxxMixWarning(LinkWarning
):
124 """Fortran and C++ objects appear together in a link line.
126 Some compilers support this, others do not.
129 class FutureReservedVariableWarning(WarningOnByDefault
):
130 """Setting a variable marked to become reserved in a future release."""
132 class MisleadingKeywordsWarning(WarningOnByDefault
):
133 """Use of possibly misspelled kwargs in Builder calls."""
135 class MissingSConscriptWarning(WarningOnByDefault
):
136 """The script specified in an SConscript() call was not found.
138 TODO: this is now an error, so no need for a warning. Left in for
139 a while in case anyone is using, remove eventually.
141 Manpage entry removed in 4.6.0.
144 class NoObjectCountWarning(WarningOnByDefault
):
145 """Object counting (debug mode) could not be enabled."""
147 class NoParallelSupportWarning(WarningOnByDefault
):
148 """Fell back to single-threaded build, as no thread support found."""
150 class ReservedVariableWarning(WarningOnByDefault
):
151 """Attempt to set reserved construction variable names."""
153 class StackSizeWarning(WarningOnByDefault
):
154 """Requested thread stack size could not be set."""
156 class TargetNotBuiltWarning(SConsWarning
): # TODO: should go to OnByDefault
157 """A target build indicated success but the file is not found."""
159 class VisualCMissingWarning(WarningOnByDefault
):
160 """Requested MSVC version not found and policy is to not fail."""
162 class VisualVersionMismatch(WarningOnByDefault
):
163 """``MSVC_VERSION`` and ``MSVS_VERSION`` do not match.
165 Note ``MSVS_VERSION`` is deprecated, use ``MSVC_VERSION``.
168 class VisualStudioMissingWarning(SConsWarning
): # TODO: unused
172 # Deprecation warnings
174 class FutureDeprecatedWarning(SConsWarning
):
175 """Base class for features that will become deprecated in a future release."""
177 class DeprecatedWarning(SConsWarning
):
178 """Base class for deprecated features, will be removed in future."""
180 class MandatoryDeprecatedWarning(DeprecatedWarning
):
181 """Base class for deprecated features where warning cannot be disabled."""
184 # Special case; base always stays DeprecatedWarning
185 class PythonVersionWarning(DeprecatedWarning
):
186 """SCons was run with a deprecated Python version."""
188 class DeprecatedOptionsWarning(MandatoryDeprecatedWarning
):
189 """Options that are deprecated."""
191 class DeprecatedDebugOptionsWarning(MandatoryDeprecatedWarning
):
192 """Option-arguments to --debug that are deprecated."""
194 class ToolQtDeprecatedWarning(DeprecatedWarning
): # TODO: unused
198 def suppressWarningClass(clazz
) -> None:
199 """Suppresses all warnings of type *clazz* or derived from *clazz*."""
200 _enabled
.insert(0, (clazz
, False))
202 def enableWarningClass(clazz
) -> None:
203 """Enables all warnings of type *clazz* or derived from *clazz*."""
204 _enabled
.insert(0, (clazz
, True))
206 def warningAsException(flag
: bool = True) -> bool:
207 """Sets global :data:`_warningAsExeption` flag.
209 If true, any enabled warning will cause an exception to be raised.
212 flag: new value for warnings-as-exceptions.
217 global _warningAsException
# pylint: disable=global-statement
218 old
= _warningAsException
219 _warningAsException
= flag
222 def warn(clazz
, *args
) -> None:
223 """Issue a warning, accounting for SCons rules.
225 Check if warnings for this class are enabled. If warnings are treated
226 as exceptions, raise exception. Use the global warning emitter
227 :data:`_warningOut`, which allows selecting different ways of
228 presenting a traceback (see Script/Main.py).
230 warning
= clazz(args
)
231 for cls
, flag
in _enabled
:
232 if isinstance(warning
, cls
):
234 if _warningAsException
:
237 if _warningOut
is not None:
241 def process_warn_strings(arguments
: Sequence
[str]) -> None:
242 """Process requests to enable/disable warnings.
244 The requests come from the option-argument string passed to the
245 ``--warn`` command line option or as the value passed to the
246 ``SetOption`` function with a first argument of ``warn``;
249 The arguments are expected to be as documented in the SCons manual
250 page for the ``--warn`` option, in the style ``some-type``,
251 which is converted here to a camel-case name like ``SomeTypeWarning``,
252 to try to match the warning classes defined here, which are then
253 passed to :func:`enableWarningClass` or :func:`suppressWarningClass`.
255 For example, a string``"deprecated"`` enables the
256 :exc:`DeprecatedWarning` class, while a string``"no-dependency"``
257 disables the :exc:`DependencyWarning` class.
259 As a special case, the string ``"all"`` disables all warnings and
260 a the string ``"no-all"`` disables all warnings.
262 def _classmunge(s
: str) -> str:
263 """Convert a warning argument to SConsCase.
265 The result is CamelCase, except "Scons" is changed to "SCons"
267 s
= s
.replace("-", " ").title().replace(" ", "")
268 return s
.replace("Scons", "SCons")
270 for arg
in arguments
:
272 if arg
.startswith("no-") and arg
not in (
274 "no-parallel-support",
277 arg
= arg
[len("no-") :]
279 class_name
= "SConsWarning"
281 class_name
= _classmunge(arg
) + 'Warning'
283 clazz
= globals()[class_name
]
285 sys
.stderr
.write(f
"No warning type: {arg!r}\n")
288 enableWarningClass(clazz
)
289 elif issubclass(clazz
, MandatoryDeprecatedWarning
):
290 sys
.stderr
.write(f
"Can not disable mandataory warning: {arg!r}\n")
292 suppressWarningClass(clazz
)
296 # indent-tabs-mode:nil
298 # vim: set expandtab tabstop=4 shiftwidth=4: