summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMats Wichmann <mats@linux.com>2023-03-22 07:45:42 -0600
committerMats Wichmann <mats@linux.com>2023-03-22 07:53:33 -0600
commit0d7dbd4b904dc6392851060d070244219cdd567d (patch)
treee5a77e1160281d7341e09110f9738c76447ed6aa
parentfd166f513214e81d3622485128739354dfa11a24 (diff)
downloadscons-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.py37
-rw-r--r--SCons/Scanner/CTests.py45
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)