[libcxx-commits] [libcxx] d085697 - [libc++] Add a new concept of ConfigAction, and use it in the DSL
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Oct 30 06:27:21 PDT 2020
Author: Louis Dionne
Date: 2020-10-30T09:27:15-04:00
New Revision: d085697013b447abd9a8779eddec606f48626bb9
URL: https://github.com/llvm/llvm-project/commit/d085697013b447abd9a8779eddec606f48626bb9
DIFF: https://github.com/llvm/llvm-project/commit/d085697013b447abd9a8779eddec606f48626bb9.diff
LOG: [libc++] Add a new concept of ConfigAction, and use it in the DSL
This will allow adding bare compiler flags through the new
configuration DSL. Previously, this would have required adding
a Lit feature for each such flag.
Differential Revision: https://reviews.llvm.org/D90429
Added:
Modified:
libcxx/test/libcxx/selftest/dsl/dsl.sh.py
libcxx/utils/libcxx/test/dsl.py
libcxx/utils/libcxx/test/features.py
libcxx/utils/libcxx/test/newconfig.py
libcxx/utils/libcxx/test/params.py
Removed:
################################################################################
diff --git a/libcxx/test/libcxx/selftest/dsl/dsl.sh.py b/libcxx/test/libcxx/selftest/dsl/dsl.sh.py
index 27c88e9e3ca7..2a51828c6163 100644
--- a/libcxx/test/libcxx/selftest/dsl/dsl.sh.py
+++ b/libcxx/test/libcxx/selftest/dsl/dsl.sh.py
@@ -275,127 +275,100 @@ class TestFeature(SetupConfigs):
def test_trivial(self):
feature = dsl.Feature(name='name')
origSubstitutions = copy.deepcopy(self.config.substitutions)
- self.assertTrue(feature.isSupported(self.config))
- feature.enableIn(self.config)
+ actions = feature.getActions(self.config)
+ self.assertTrue(len(actions) == 1)
+ for a in actions:
+ a.applyTo(self.config)
self.assertEqual(origSubstitutions, self.config.substitutions)
self.assertIn('name', self.config.available_features)
def test_name_can_be_a_callable(self):
feature = dsl.Feature(name=lambda cfg: 'name')
- assert feature.isSupported(self.config)
- self.assertEqual('name', feature.getName(self.config))
- feature.enableIn(self.config)
+ for a in feature.getActions(self.config):
+ a.applyTo(self.config)
self.assertIn('name', self.config.available_features)
def test_name_is_not_a_string_1(self):
feature = dsl.Feature(name=None)
- assert feature.isSupported(self.config)
- self.assertRaises(ValueError, lambda: feature.getName(self.config))
- self.assertRaises(ValueError, lambda: feature.enableIn(self.config))
+ self.assertRaises(ValueError, lambda: feature.getActions(self.config))
+ self.assertRaises(ValueError, lambda: feature.pretty(self.config))
def test_name_is_not_a_string_2(self):
feature = dsl.Feature(name=lambda cfg: None)
- assert feature.isSupported(self.config)
- self.assertRaises(ValueError, lambda: feature.getName(self.config))
- self.assertRaises(ValueError, lambda: feature.enableIn(self.config))
+ self.assertRaises(ValueError, lambda: feature.getActions(self.config))
+ self.assertRaises(ValueError, lambda: feature.pretty(self.config))
- def test_getName_when_unsupported(self):
- feature = dsl.Feature(name='name', when=lambda _: False)
- assert not feature.isSupported(self.config)
- self.assertRaises(AssertionError, lambda: feature.getName(self.config))
-
- def test_adding_compile_flag(self):
- feature = dsl.Feature(name='name', compileFlag='-foo')
+ def test_adding_action(self):
+ feature = dsl.Feature(name='name', actions=[dsl.AddCompileFlag('-std=c++03')])
origLinkFlags = copy.deepcopy(self.getSubstitution('%{link_flags}'))
- assert feature.isSupported(self.config)
- feature.enableIn(self.config)
+ for a in feature.getActions(self.config):
+ a.applyTo(self.config)
self.assertIn('name', self.config.available_features)
- self.assertIn('-foo', self.getSubstitution('%{compile_flags}'))
+ self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}'))
self.assertEqual(origLinkFlags, self.getSubstitution('%{link_flags}'))
- def test_compile_flag_can_be_a_callable(self):
+ def test_actions_can_be_a_callable(self):
feature = dsl.Feature(name='name',
- compileFlag=lambda cfg: (self.assertIs(self.config, cfg), '-foo')[1])
- assert feature.isSupported(self.config)
- feature.enableIn(self.config)
- self.assertIn('-foo', self.getSubstitution('%{compile_flags}'))
-
- def test_adding_link_flag(self):
- feature = dsl.Feature(name='name', linkFlag='-foo')
- origCompileFlags = copy.deepcopy(self.getSubstitution('%{compile_flags}'))
- assert feature.isSupported(self.config)
- feature.enableIn(self.config)
- self.assertIn('name', self.config.available_features)
- self.assertIn('-foo', self.getSubstitution('%{link_flags}'))
- self.assertEqual(origCompileFlags, self.getSubstitution('%{compile_flags}'))
-
- def test_link_flag_can_be_a_callable(self):
- feature = dsl.Feature(name='name',
- linkFlag=lambda cfg: (self.assertIs(self.config, cfg), '-foo')[1])
- assert feature.isSupported(self.config)
- feature.enableIn(self.config)
- self.assertIn('-foo', self.getSubstitution('%{link_flags}'))
-
- def test_adding_both_flags(self):
- feature = dsl.Feature(name='name', compileFlag='-hello', linkFlag='-world')
- assert feature.isSupported(self.config)
- feature.enableIn(self.config)
- self.assertIn('name', self.config.available_features)
-
- self.assertIn('-hello', self.getSubstitution('%{compile_flags}'))
- self.assertNotIn('-world', self.getSubstitution('%{compile_flags}'))
-
- self.assertIn('-world', self.getSubstitution('%{link_flags}'))
- self.assertNotIn('-hello', self.getSubstitution('%{link_flags}'))
+ actions=lambda cfg: (
+ self.assertIs(self.config, cfg),
+ [dsl.AddCompileFlag('-std=c++03')]
+ )[1])
+ for a in feature.getActions(self.config):
+ a.applyTo(self.config)
+ self.assertIn('-std=c++03', self.getSubstitution('%{compile_flags}'))
def test_unsupported_feature(self):
feature = dsl.Feature(name='name', when=lambda _: False)
- self.assertFalse(feature.isSupported(self.config))
- # Also make sure we assert if we ever try to add it to a config
- self.assertRaises(AssertionError, lambda: feature.enableIn(self.config))
+ self.assertEqual(feature.getActions(self.config), [])
def test_is_supported_gets_passed_the_config(self):
feature = dsl.Feature(name='name', when=lambda cfg: (self.assertIs(self.config, cfg), True)[1])
- self.assertTrue(feature.isSupported(self.config))
+ self.assertEqual(len(feature.getActions(self.config)), 1)
+
+def _throw():
+ raise ValueError()
class TestParameter(SetupConfigs):
"""
Tests for libcxx.test.dsl.Parameter
"""
def test_empty_name_should_blow_up(self):
- self.assertRaises(ValueError, lambda: dsl.Parameter(name='', choices=['c++03'], type=str, help='', feature=lambda _: None))
+ self.assertRaises(ValueError, lambda: dsl.Parameter(name='', choices=['c++03'], type=str, help='', actions=lambda _: []))
def test_empty_choices_should_blow_up(self):
- self.assertRaises(ValueError, lambda: dsl.Parameter(name='std', choices=[], type=str, help='', feature=lambda _: None))
+ self.assertRaises(ValueError, lambda: dsl.Parameter(name='std', choices=[], type=str, help='', actions=lambda _: []))
def test_name_is_set_correctly(self):
- param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', feature=lambda _: None)
+ param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: [])
self.assertEqual(param.name, 'std')
def test_no_value_provided_and_no_default_value(self):
- param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', feature=lambda _: None)
- self.assertRaises(ValueError, lambda: param.getFeature(self.config, self.litConfig.params))
+ param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', actions=lambda _: [])
+ self.assertRaises(ValueError, lambda: param.getActions(self.config, self.litConfig.params))
def test_no_value_provided_and_default_value(self):
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='', default='c++03',
- feature=lambda std: dsl.Feature(name=std))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda std: [dsl.AddFeature(std)])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('c++03', self.config.available_features)
def test_value_provided_on_command_line_and_no_default_value(self):
self.litConfig.params['std'] = 'c++03'
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='',
- feature=lambda std: dsl.Feature(name=std))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda std: [dsl.AddFeature(std)])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('c++03', self.config.available_features)
def test_value_provided_on_command_line_and_default_value(self):
"""The value provided on the command line should override the default value"""
self.litConfig.params['std'] = 'c++11'
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='',
- feature=lambda std: dsl.Feature(name=std))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda std: [dsl.AddFeature(std)])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('c++11', self.config.available_features)
self.assertNotIn('c++03', self.config.available_features)
@@ -403,8 +376,9 @@ def test_value_provided_in_config_and_default_value(self):
"""The value provided in the config should override the default value"""
self.config.std ='c++11'
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, default='c++03', help='',
- feature=lambda std: dsl.Feature(name=std))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda std: [dsl.AddFeature(std)])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('c++11', self.config.available_features)
self.assertNotIn('c++03', self.config.available_features)
@@ -413,42 +387,45 @@ def test_value_provided_in_config_and_on_command_line(self):
self.config.std = 'c++11'
self.litConfig.params['std'] = 'c++03'
param = dsl.Parameter(name='std', choices=['c++03', 'c++11'], type=str, help='',
- feature=lambda std: dsl.Feature(name=std))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda std: [dsl.AddFeature(std)])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('c++03', self.config.available_features)
self.assertNotIn('c++11', self.config.available_features)
- def test_feature_is_None(self):
+ def test_no_actions(self):
self.litConfig.params['std'] = 'c++03'
param = dsl.Parameter(name='std', choices=['c++03'], type=str, help='',
- feature=lambda _: None)
- feature = param.getFeature(self.config, self.litConfig.params)
- self.assertIsNone(feature)
+ actions=lambda _: [])
+ actions = param.getActions(self.config, self.litConfig.params)
+ self.assertEqual(actions, [])
def test_boolean_value_parsed_from_trueish_string_parameter(self):
self.litConfig.params['enable_exceptions'] = "True"
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
- feature=lambda exceptions: None if exceptions else ValueError())
- self.assertIsNone(param.getFeature(self.config, self.litConfig.params))
+ actions=lambda exceptions: [] if exceptions else _throw())
+ self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
def test_boolean_value_from_true_boolean_parameter(self):
self.litConfig.params['enable_exceptions'] = True
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
- feature=lambda exceptions: None if exceptions else ValueError())
- self.assertIsNone(param.getFeature(self.config, self.litConfig.params))
+ actions=lambda exceptions: [] if exceptions else _throw())
+ self.assertEqual(param.getActions(self.config, self.litConfig.params), [])
def test_boolean_value_parsed_from_falseish_string_parameter(self):
self.litConfig.params['enable_exceptions'] = "False"
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
- feature=lambda exceptions: None if exceptions else dsl.Feature(name="-fno-exceptions"))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('-fno-exceptions', self.config.available_features)
def test_boolean_value_from_false_boolean_parameter(self):
self.litConfig.params['enable_exceptions'] = False
param = dsl.Parameter(name='enable_exceptions', choices=[True, False], type=bool, help='',
- feature=lambda exceptions: None if exceptions else dsl.Feature(name="-fno-exceptions"))
- param.getFeature(self.config, self.litConfig.params).enableIn(self.config)
+ actions=lambda exceptions: [] if exceptions else [dsl.AddFeature("-fno-exceptions")])
+ for a in param.getActions(self.config, self.litConfig.params):
+ a.applyTo(self.config)
self.assertIn('-fno-exceptions', self.config.available_features)
diff --git a/libcxx/utils/libcxx/test/dsl.py b/libcxx/utils/libcxx/test/dsl.py
index 6a02ae634907..14d3a0eff3c4 100644
--- a/libcxx/utils/libcxx/test/dsl.py
+++ b/libcxx/utils/libcxx/test/dsl.py
@@ -217,6 +217,124 @@ def featureTestMacros(config, flags=''):
return {m: int(v.rstrip('LlUu')) for (m, v) in allMacros.items() if m.startswith('__cpp_')}
+def _addToSubstitution(substitutions, key, value):
+ return [(k, v + ' ' + value) if k == key else (k, v) for (k, v) in substitutions]
+
+
+class ConfigAction(object):
+ """
+ This class represents an action that can be performed on a Lit TestingConfig
+ object.
+
+ Examples of such actions are adding or modifying substitutions, Lit features,
+ etc. This class only provides the interface of such actions, and it is meant
+ to be subclassed appropriately to create new actions.
+ """
+ def applyTo(self, config):
+ """
+ Applies the action to the given configuration.
+
+ This should modify the configuration object in place, and return nothing.
+
+ If applying the action to the configuration would yield an invalid
+ configuration, and it is possible to diagnose it here, this method
+ should produce an error. For example, it should be an error to modify
+ a substitution in a way that we know for sure is invalid (e.g. adding
+ a compiler flag when we know the compiler doesn't support it). Failure
+ to do so early may lead to
diff icult-to-diagnose issues down the road.
+ """
+ pass
+
+ def pretty(self, config, litParams):
+ """
+ Returns a short and human-readable string describing what this action does.
+
+ This is used for logging purposes when running the test suite, so it should
+ be kept concise.
+ """
+ pass
+
+
+class AddFeature(ConfigAction):
+ """
+ This action defines the given Lit feature when running the test suite.
+
+ The name of the feature can be a string or a callable, in which case it is
+ called with the configuration to produce the feature name (as a string).
+ """
+ def __init__(self, name):
+ self._name = name
+
+ def _getName(self, config):
+ name = self._name(config) if callable(self._name) else self._name
+ if not isinstance(name, str):
+ raise ValueError("Lit feature did not resolve to a string (got {})".format(name))
+ return name
+
+ def applyTo(self, config):
+ config.available_features.add(self._getName(config))
+
+ def pretty(self, config, litParams):
+ return 'add Lit feature {}'.format(self._getName(config))
+
+
+class AddFlag(ConfigAction):
+ """
+ This action adds the given flag to the %{flags} substitution.
+
+ The flag can be a string or a callable, in which case it is called with the
+ configuration to produce the actual flag (as a string).
+ """
+ def __init__(self, flag):
+ self._getFlag = lambda config: flag(config) if callable(flag) else flag
+
+ def applyTo(self, config):
+ flag = self._getFlag(config)
+ assert hasCompileFlag(config, flag), "Trying to enable flag {}, which is not supported".format(flag)
+ config.substitutions = _addToSubstitution(config.substitutions, '%{flags}', flag)
+
+ def pretty(self, config, litParams):
+ return 'add {} to %{{flags}}'.format(self._getFlag(config))
+
+
+class AddCompileFlag(ConfigAction):
+ """
+ This action adds the given flag to the %{compile_flags} substitution.
+
+ The flag can be a string or a callable, in which case it is called with the
+ configuration to produce the actual flag (as a string).
+ """
+ def __init__(self, flag):
+ self._getFlag = lambda config: flag(config) if callable(flag) else flag
+
+ def applyTo(self, config):
+ flag = self._getFlag(config)
+ assert hasCompileFlag(config, flag), "Trying to enable compile flag {}, which is not supported".format(flag)
+ config.substitutions = _addToSubstitution(config.substitutions, '%{compile_flags}', flag)
+
+ def pretty(self, config, litParams):
+ return 'add {} to %{{compile_flags}}'.format(self._getFlag(config))
+
+
+class AddLinkFlag(ConfigAction):
+ """
+ This action adds the given flag to the %{link_flags} substitution.
+
+ The flag can be a string or a callable, in which case it is called with the
+ configuration to produce the actual flag (as a string).
+ """
+ def __init__(self, flag):
+ self._getFlag = lambda config: flag(config) if callable(flag) else flag
+
+ def applyTo(self, config):
+ flag = self._getFlag(config)
+ assert hasCompileFlag(config, flag), "Trying to enable link flag {}, which is not supported".format(flag)
+ config.substitutions = _addToSubstitution(config.substitutions, '%{link_flags}', flag)
+
+ def pretty(self, config, litParams):
+ return 'add {} to %{{link_flags}}'.format(self._getFlag(config))
+
+
class Feature(object):
"""
Represents a Lit available feature that is enabled whenever it is supported.
@@ -226,7 +344,7 @@ class Feature(object):
control whether a Feature is enabled -- it should be enabled whenever it
is supported.
"""
- def __init__(self, name, compileFlag=None, linkFlag=None, when=lambda _: True):
+ def __init__(self, name, actions=None, when=lambda _: True):
"""
Create a Lit feature for consumption by a test suite.
@@ -236,17 +354,13 @@ def __init__(self, name, compileFlag=None, linkFlag=None, when=lambda _: True):
callable, in which case it is passed the TestingConfig and should
generate a string representing the name of the feature.
- - compileFlag
- An optional compile flag to add when this feature is added to a
- TestingConfig. If provided, this must be a string representing a
- compile flag that will be appended to the end of the %{compile_flags}
- substitution of the TestingConfig.
-
- - linkFlag
- An optional link flag to add when this feature is added to a
- TestingConfig. If provided, this must be a string representing a
- link flag that will be appended to the end of the %{link_flags}
- substitution of the TestingConfig.
+ - actions
+ An optional list of ConfigActions to apply when the feature is supported.
+ An AddFeature action is always created regardless of any actions supplied
+ here -- these actions are meant to perform more than setting a corresponding
+ Lit feature (e.g. adding compiler flags). If 'actions' is a callable, it
+ is called with the current configuration object to generate the actual
+ list of actions.
- when
A callable that gets passed a TestingConfig and should return a
@@ -257,52 +371,35 @@ def __init__(self, name, compileFlag=None, linkFlag=None, when=lambda _: True):
supported.
"""
self._name = name
- self._compileFlag = compileFlag
- self._linkFlag = linkFlag
+ self._actions = [] if actions is None else actions
self._isSupported = when
- def isSupported(self, config):
- """
- Return whether the feature is supported by the given TestingConfig.
- """
- return self._isSupported(config)
-
- def getName(self, config):
- """
- Return the name of the feature.
-
- It is an error to call `f.getName(cfg)` if the feature `f` is not supported.
- """
- assert self.isSupported(config), \
- "Trying to get the name of a feature that is not supported in the given configuration"
+ def _getName(self, config):
name = self._name(config) if callable(self._name) else self._name
if not isinstance(name, str):
raise ValueError("Feature did not resolve to a name that's a string, got {}".format(name))
return name
- def enableIn(self, config):
+ def getActions(self, config):
"""
- Enable a feature in a TestingConfig.
+ Return the list of actions associated to this feature.
- The name of the feature is added to the set of available features of
- `config`, and any compile or link flags provided upon construction of
- the Feature are added to the end of the corresponding substitution in
- the config.
-
- It is an error to call `f.enableIn(cfg)` if the feature `f` is not
- supported in that TestingConfig (i.e. if `not f.isSupported(cfg)`).
+ If the feature is not supported, an empty list is returned.
+ If the feature is supported, an `AddFeature` action is automatically added
+ to the returned list of actions, in addition to any actions provided on
+ construction.
"""
- assert self.isSupported(config), \
- "Trying to enable feature {} that is not supported in the given configuration".format(self._name)
+ if not self._isSupported(config):
+ return []
+ else:
+ actions = self._actions(config) if callable(self._actions) else self._actions
+ return [AddFeature(self._getName(config))] + actions
- addTo = lambda subs, sub, flag: [(s, x + ' ' + flag) if s == sub else (s, x) for (s, x) in subs]
- if self._compileFlag:
- compileFlag = self._compileFlag(config) if callable(self._compileFlag) else self._compileFlag
- config.substitutions = addTo(config.substitutions, '%{compile_flags}', compileFlag)
- if self._linkFlag:
- linkFlag = self._linkFlag(config) if callable(self._linkFlag) else self._linkFlag
- config.substitutions = addTo(config.substitutions, '%{link_flags}', linkFlag)
- config.available_features.add(self.getName(config))
+ def pretty(self, config):
+ """
+ Returns the Feature's name.
+ """
+ return self._getName(config)
def _str_to_bool(s):
@@ -339,11 +436,13 @@ class Parameter(object):
that use that `config` object.
Parameters can have multiple possible values, and they can have a default
- value when left unspecified. They can also have a Feature associated to them,
- in which case the Feature is added to the TestingConfig if the parameter is
- enabled. It is an error if the Parameter is enabled but the Feature associated
- to it is not supported, for example trying to set the compilation standard to
- C++17 when `-std=c++17` is not supported by the compiler.
+ value when left unspecified. They can also have any number of ConfigActions
+ associated to them, in which case the actions will be performed on the
+ TestingConfig if the parameter is enabled. Depending on the actions
+ associated to a Parameter, it may be an error to enable the Parameter
+ if some actions are not supported in the given configuration. For example,
+ trying to set the compilation standard to C++23 when `-std=c++23` is not
+ supported by the compiler would be an error.
One important point is that Parameters customize the behavior of the test
suite in a bounded way, i.e. there should be a finite set of possible choices
@@ -356,7 +455,7 @@ class Parameter(object):
compiler), it can be handled in the `lit.cfg`, but it shouldn't be
represented with a Parameter.
"""
- def __init__(self, name, choices, type, help, feature, default=None):
+ def __init__(self, name, choices, type, help, actions, default=None):
"""
Create a Lit parameter to customize the behavior of a test suite.
@@ -380,10 +479,11 @@ def __init__(self, name, choices, type, help, feature, default=None):
A string explaining the parameter, for documentation purposes.
TODO: We should be able to surface those from the Lit command-line.
- - feature
+ - actions
A callable that gets passed the parsed value of the parameter (either
the one passed on the command-line or the default one), and that returns
- either None or a Feature.
+ a list of ConfigAction to perform given the value of the parameter.
+ All the ConfigAction must be supported in the given configuration.
- default
An optional default value to use for the parameter when no value is
@@ -403,20 +503,13 @@ def __init__(self, name, choices, type, help, feature, default=None):
self._parse = lambda x: (_str_to_bool(x) if type is bool and isinstance(x, str)
else type(x))
self._help = help
- self._feature = feature
+ self._actions = actions
self._default = default
- @property
- def name(self):
+ def _getValue(self, config, litParams):
"""
- Return the name of the parameter.
-
- This is the name that can be used to set the parameter on the command-line
- when running Lit.
+ Return the value of the parameter given the configuration objects.
"""
- return self._name
-
- def getFeature(self, config, litParams):
param = getattr(config, self.name, None)
param = litParams.get(self.name, param)
if param is None and self._default is None:
@@ -425,4 +518,26 @@ def getFeature(self, config, litParams):
value = self._parse(param) if param is not None else getDefault()
if value not in self._choices:
raise ValueError("Got value '{}' for parameter '{}', which is not in the provided set of possible choices: {}".format(value, self.name, self._choices))
- return self._feature(value)
+ return value
+
+ @property
+ def name(self):
+ """
+ Return the name of the parameter.
+
+ This is the name that can be used to set the parameter on the command-line
+ when running Lit.
+ """
+ return self._name
+
+ def getActions(self, config, litParams):
+ """
+ Return the list of actions associated to this value of the parameter.
+ """
+ return self._actions(self._getValue(config, litParams))
+
+ def pretty(self, config, litParams):
+ """
+ Return a pretty representation of the parameter's name and value.
+ """
+ return "{}={}".format(self.name, self._getValue(config, litParams))
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 53509d95ae21..cacbf6dac0ea 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -14,11 +14,19 @@
_isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg)
DEFAULT_FEATURES = [
- Feature(name='fcoroutines-ts', compileFlag='-fcoroutines-ts',
+ Feature(name='fcoroutines-ts',
when=lambda cfg: hasCompileFlag(cfg, '-fcoroutines-ts') and
- featureTestMacros(cfg, flags='-fcoroutines-ts').get('__cpp_coroutines', 0) >= 201703),
+ featureTestMacros(cfg, flags='-fcoroutines-ts').get('__cpp_coroutines', 0) >= 201703,
+ actions=[AddCompileFlag('-fcoroutines-ts')]),
+
+ Feature(name='thread-safety',
+ when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'),
+ actions=[AddCompileFlag('-Werror=thread-safety')]),
+
+ Feature(name='diagnose-if-support',
+ when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'),
+ actions=[AddCompileFlag('-Wuser-defined-warnings')]),
- Feature(name='thread-safety', when=lambda cfg: hasCompileFlag(cfg, '-Werror=thread-safety'), compileFlag='-Werror=thread-safety'),
Feature(name='has-fblocks', when=lambda cfg: hasCompileFlag(cfg, '-fblocks')),
Feature(name='-fsized-deallocation', when=lambda cfg: hasCompileFlag(cfg, '-fsized-deallocation')),
Feature(name='-faligned-allocation', when=lambda cfg: hasCompileFlag(cfg, '-faligned-allocation')),
@@ -30,7 +38,6 @@
Feature(name='has-fobjc-arc', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc') and
sys.platform.lower().strip() == 'darwin'), # TODO: this doesn't handle cross-compiling to Apple platforms.
Feature(name='objective-c++', when=lambda cfg: hasCompileFlag(cfg, '-xobjective-c++ -fobjc-arc')),
- Feature(name='diagnose-if-support', when=lambda cfg: hasCompileFlag(cfg, '-Wuser-defined-warnings'), compileFlag='-Wuser-defined-warnings'),
Feature(name='modules-support', when=lambda cfg: hasCompileFlag(cfg, '-fmodules')),
Feature(name='non-lockfree-atomics', when=lambda cfg: sourceBuilds(cfg, """
#include <atomic>
@@ -87,9 +94,11 @@
# FIXME: This is a hack that should be fixed using module maps.
# If modules are enabled then we have to lift all of the definitions
# in <__config_site> onto the command line.
- compileFlag=lambda cfg, m=macro: '-Wno-macro-redefined -D{}'.format(m) + (
- '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
- )
+ actions=lambda cfg, m=macro: [
+ AddCompileFlag('-Wno-macro-redefined -D{}'.format(m) + (
+ '={}'.format(compilerMacros(cfg)[m]) if compilerMacros(cfg)[m] else ''
+ ))
+ ]
)
]
diff --git a/libcxx/utils/libcxx/test/newconfig.py b/libcxx/utils/libcxx/test/newconfig.py
index 8996484ba20b..644438724f7e 100644
--- a/libcxx/utils/libcxx/test/newconfig.py
+++ b/libcxx/utils/libcxx/test/newconfig.py
@@ -13,23 +13,25 @@ def _getSubstitution(substitution, config):
raise ValueError('Substitution {} is not in the config.'.format(substitution))
def configure(parameters, features, config, lit_config):
- # Apply parameters to the configuration first, since parameters are things
- # that we request explicitly and which might influence what features are
- # implicitly made available next.
+ # Apply the actions supplied by parameters to the configuration first, since
+ # parameters are things that we request explicitly and which might influence
+ # what features are implicitly made available next.
for param in parameters:
- feature = param.getFeature(config, lit_config.params)
- if feature:
- feature.enableIn(config)
- lit_config.note("Enabling Lit feature '{}' as a result of parameter '{}'".format(feature.getName(config), param.name))
+ actions = param.getActions(config, lit_config.params)
+ for action in actions:
+ action.applyTo(config)
+ lit_config.note("Applied '{}' as a result of parameter '{}'".format(
+ action.pretty(config, lit_config.params),
+ param.pretty(config, lit_config.params)))
# Then, apply the automatically-detected features.
- printFeatures = []
for feature in features:
- if feature.isSupported(config):
- feature.enableIn(config)
- printFeatures.append(feature.getName(config))
- printFeatures = ["'{}'".format(f) for f in sorted(printFeatures)]
- lit_config.note("Enabling implicitly detected Lit features {}".format(', '.join(printFeatures)))
+ actions = feature.getActions(config)
+ for action in actions:
+ action.applyTo(config)
+ lit_config.note("Applied '{}' as a result of implicitly detected feature '{}'".format(
+ action.pretty(config, lit_config.params),
+ feature.pretty(config)))
# Print the basic substitutions
for sub in ('%{cxx}', '%{flags}', '%{compile_flags}', '%{link_flags}', '%{exec}'):
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 94686a66b05a..8e6e4234d6ed 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -15,40 +15,54 @@
Parameter(name='std', choices=_allStandards, type=str,
help="The version of the standard to compile the test suite with.",
default=lambda cfg: next(s for s in reversed(_allStandards) if hasCompileFlag(cfg, '-std='+s)),
- feature=lambda std:
- Feature(name=std, compileFlag='-std={}'.format(std),
- when=lambda cfg: hasCompileFlag(cfg, '-std={}'.format(std)))),
+ actions=lambda std: [
+ AddFeature(std),
+ AddCompileFlag('-std={}'.format(std)),
+ ]),
Parameter(name='enable_exceptions', choices=[True, False], type=bool, default=True,
help="Whether to enable exceptions when compiling the test suite.",
- feature=lambda exceptions: None if exceptions else
- Feature(name='no-exceptions', compileFlag='-fno-exceptions')),
+ actions=lambda exceptions: [] if exceptions else [
+ AddFeature('no-exceptions'),
+ AddCompileFlag('-fno-exceptions')
+ ]),
Parameter(name='enable_rtti', choices=[True, False], type=bool, default=True,
help="Whether to enable RTTI when compiling the test suite.",
- feature=lambda rtti: None if rtti else
- Feature(name='no-rtti', compileFlag='-fno-rtti')),
+ actions=lambda rtti: [] if rtti else [
+ AddFeature('no-rtti'),
+ AddCompileFlag('-fno-rtti')
+ ]),
Parameter(name='stdlib', choices=['libc++', 'libstdc++', 'msvc'], type=str, default='libc++',
help="The C++ Standard Library implementation being tested.",
- feature=lambda stdlib: Feature(name=stdlib)),
+ actions=lambda stdlib: [
+ AddFeature(stdlib)
+ ]),
# Parameters to enable or disable parts of the test suite
Parameter(name='enable_filesystem', choices=[True, False], type=bool, default=True,
help="Whether to enable tests for the C++ <filesystem> library.",
- feature=lambda filesystem: None if filesystem else
- Feature(name='c++filesystem-disabled')),
+ actions=lambda filesystem: [] if filesystem else [
+ AddFeature('c++filesystem-disabled')
+ ]),
Parameter(name='enable_experimental', choices=[True, False], type=bool, default=False,
- help="Whether to enable tests for experimental C++ libraries (typically Library Fundamentals TSes).",
- feature=lambda experimental: None if not experimental else
- Feature(name='c++experimental', linkFlag='-lc++experimental')),
+ help="Whether to enable tests for experimental C++ libraries (typically Library Fundamentals TSes).",
+ actions=lambda experimental: [] if not experimental else [
+ AddFeature('c++experimental'),
+ AddLinkFlag('-lc++experimental')
+ ]),
Parameter(name='long_tests', choices=[True, False], type=bool, default=True,
help="Whether to enable tests that take longer to run. This can be useful when running on a very slow device.",
- feature=lambda enabled: Feature(name='long_tests') if enabled else None),
+ actions=lambda enabled: [] if not enabled else [
+ AddFeature('long_tests')
+ ]),
Parameter(name='enable_debug_tests', choices=[True, False], type=bool, default=True,
help="Whether to enable tests that exercise the libc++ debugging mode.",
- feature=lambda enabled: None if enabled else Feature(name='libcxx-no-debug-mode')),
+ actions=lambda enabled: [] if enabled else [
+ AddFeature('libcxx-no-debug-mode')
+ ]),
]
More information about the libcxx-commits
mailing list