diff options
author | Mats Wichmann <mats@linux.com> | 2023-03-22 07:45:42 -0600 |
---|---|---|
committer | Mats Wichmann <mats@linux.com> | 2023-03-22 07:53:33 -0600 |
commit | 0d7dbd4b904dc6392851060d070244219cdd567d (patch) | |
tree | e5a77e1160281d7341e09110f9738c76447ed6aa | |
parent | fd166f513214e81d3622485128739354dfa11a24 (diff) | |
download | scons-git-0d7dbd4b904dc6392851060d070244219cdd567d.tar.gz |
dictify_CPPDEFINES: also handle single tuple
* Single-tuple CPPDEFINES was not handled.
* Add some more unit tests.
* Add some comments - that we need to keep in sync with processDefines,
but don't actually call it (the routine *could* be rewritten to process
the result of processDefines instead of the bare CPPDEFINES, but
currently doesn't do that).
Signed-off-by: Mats Wichmann <mats@linux.com>
-rw-r--r-- | SCons/Scanner/C.py | 37 | ||||
-rw-r--r-- | SCons/Scanner/CTests.py | 45 |
2 files changed, 60 insertions, 22 deletions
diff --git a/SCons/Scanner/C.py b/SCons/Scanner/C.py index 418454ff6..31ab7e62e 100644 --- a/SCons/Scanner/C.py +++ b/SCons/Scanner/C.py @@ -21,7 +21,12 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""Dependency scanner for C/C++ code.""" +"""Dependency scanner for C/C++ code. + +Two scanners are defined here: the default CScanner, and the optional +CConditionalScanner, which must be explicitly selected by calling +add_scanner() for each affected suffix. +""" import SCons.Node.FS import SCons.cpp @@ -62,11 +67,30 @@ class SConsCPPScanner(SCons.cpp.PreProcessor): return '' def dictify_CPPDEFINES(env) -> dict: - """Returns CPPDEFINES converted to a dict.""" + """Returns CPPDEFINES converted to a dict. + + This should be similar to :func:`~SCons.Defaults.processDefines`. + Unfortunately, we can't do the simple thing of calling that routine and + passing the result to the dict() constructor, because it turns the defines + into a list of "name=value" pairs, which the dict constructor won't + consume correctly. Also cannot just call dict on CPPDEFINES itself - it's + fine if it's stored in the converted form (currently deque of tuples), but + CPPDEFINES could be in other formats too. + + So we have to do all the work here - keep concepts in sync with + ``processDefines``. + """ cppdefines = env.get('CPPDEFINES', {}) result = {} if cppdefines is None: return result + + if SCons.Util.is_Tuple(cppdefines): + try: + return {cppdefines[0]: cppdefines[1]} + except IndexError: + return {cppdefines[0]: None} + if SCons.Util.is_Sequence(cppdefines): for c in cppdefines: if SCons.Util.is_Sequence(c): @@ -85,15 +109,18 @@ def dictify_CPPDEFINES(env) -> dict: # don't really know what to do here result[c] = None return result + if SCons.Util.is_String(cppdefines): try: name, value = cppdefines.split('=') return {name: value} except ValueError: return {cppdefines: None} - if not SCons.Util.is_Dict(cppdefines): - return {cppdefines: None} - return cppdefines + + if SCons.Util.is_Dict(cppdefines): + return cppdefines + + return {cppdefines: None} class SConsCPPScannerWrapper: """The SCons wrapper around a cpp.py scanner. diff --git a/SCons/Scanner/CTests.py b/SCons/Scanner/CTests.py index e9780d0fc..0f62198d6 100644 --- a/SCons/Scanner/CTests.py +++ b/SCons/Scanner/CTests.py @@ -516,16 +516,14 @@ class CConditionalScannerTestCase4(unittest.TestCase): def runTest(self): """Test that dependency is detected if #include uses a macro.""" - # first try the macro defined in the source file - with self.subTest(): + with self.subTest("macro defined in the source file"): env = DummyEnvironment() s = SCons.Scanner.C.CConditionalScanner() deps = s(env.File('f9a.c'), env, s.path(env)) headers = ['f9.h'] deps_match(self, deps, headers) - # then try the macro defined on the command line - with self.subTest(): + with self.subTest("macro defined on the command line"): env = DummyEnvironment(CPPDEFINES='HEADER=\\"f9.h\\"') #env = DummyEnvironment(CPPDEFINES=['HEADER=\\"f9.h\\"']) s = SCons.Scanner.C.CConditionalScanner() @@ -536,29 +534,42 @@ class CConditionalScannerTestCase4(unittest.TestCase): class dictify_CPPDEFINESTestCase(unittest.TestCase): def runTest(self): - """Make sure single-item tuples convert correctly. + """Make sure CPPDEFINES converts correctly. - This is a regression test: AppendUnique turns sequences into - lists of tuples, and dictify could gack on these. + Various types and combinations of types could fail if not handled + specifically by dictify_CPPDEFINES - this is a regression test. """ - with self.subTest(): - env = DummyEnvironment(CPPDEFINES=[("VALUED_DEFINE", 1), ("UNVALUED_DEFINE", )]) + with self.subTest("tuples in a sequence, including one without value"): + env = DummyEnvironment(CPPDEFINES=[("VALUED", 1), ("UNVALUED",)]) d = SCons.Scanner.C.dictify_CPPDEFINES(env) - expect = {'VALUED_DEFINE': 1, 'UNVALUED_DEFINE': None} + expect = {"VALUED": 1, "UNVALUED": None} self.assertEqual(d, expect) - # string-valued define in a sequence - with self.subTest(): - env = DummyEnvironment(CPPDEFINES=["STRING=VALUE"]) + with self.subTest("tuple-valued define by itself"): + env = DummyEnvironment(CPPDEFINES=("STRING", "VALUE")) d = SCons.Scanner.C.dictify_CPPDEFINES(env) - expect = {'STRING': 'VALUE'} + expect = {"STRING": "VALUE"} self.assertEqual(d, expect) - # string-valued define by itself - with self.subTest(): + with self.subTest("string-valued define in a sequence"): + env = DummyEnvironment(CPPDEFINES=[("STRING=VALUE")]) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE"} + self.assertEqual(d, expect) + + with self.subTest("string-valued define by itself"): env = DummyEnvironment(CPPDEFINES="STRING=VALUE") d = SCons.Scanner.C.dictify_CPPDEFINES(env) - expect = {'STRING': 'VALUE'} + expect = {"STRING": "VALUE"} + self.assertEqual(d, expect) + + from collections import deque + with self.subTest("compound CPPDEFINES in internal format"): + env = DummyEnvironment( + CPPDEFINES=deque([("STRING", "VALUE"), ("UNVALUED",)]) + ) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE", "UNVALUED": None} self.assertEqual(d, expect) |