@@ -40,6 +40,7 @@ def __init__(self, name, data, unit_name, unit_kind):
4040 self .value = data .get ("value" , None )
4141 self .required = data .get ("required" , False )
4242 self .macro_name = data .get ("macro_name" , "MBED_CONF_%s" % self .sanitize (self .name .upper ()))
43+ self .config_errors = []
4344
4445 # Return the full (prefixed) name of a parameter.
4546 # If the parameter already has a prefix, check if it is valid
@@ -147,6 +148,11 @@ class Config:
147148 "application" : set (["config" , "custom_targets" , "target_overrides" , "macros" , "__config_path" ])
148149 }
149150
151+ # Allowed features in configurations
152+ __allowed_features = [
153+ "UVISOR" , "BLE" , "CLIENT" , "IPV4" , "IPV6"
154+ ]
155+
150156 # The initialization arguments for Config are:
151157 # target: the name of the mbed target used for this configuration instance
152158 # top_level_dirs: a list of top level source directories (where mbed_abb_config.json could be found)
@@ -176,7 +182,9 @@ def __init__(self, target, top_level_dirs = []):
176182 self .processed_configs = {}
177183 self .target = target if isinstance (target , str ) else target .name
178184 self .target_labels = Target .get_target (self .target ).get_labels ()
179- self .target_instance = Target .get_target (self .target )
185+ self .added_features = set ()
186+ self .removed_features = set ()
187+ self .removed_unecessary_features = False
180188
181189 # Add one or more configuration files
182190 def add_config_files (self , flist ):
@@ -212,44 +220,59 @@ def _process_config_parameters(self, data, params, unit_name, unit_kind):
212220 params [full_name ] = ConfigParameter (name , v if isinstance (v , dict ) else {"value" : v }, unit_name , unit_kind )
213221 return params
214222
223+ # Add features to the available features
224+ def remove_features (self , features ):
225+ for feature in features :
226+ if feature in self .added_features :
227+ raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
228+
229+ self .removed_features |= set (features )
230+
231+ # Remove features from the available features
232+ def add_features (self , features ):
233+ for feature in features :
234+ if (feature in self .removed_features
235+ or (self .removed_unecessary_features and feature not in self .added_features )):
236+ raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
237+
238+ self .added_features |= set (features )
239+
215240 # Helper function: process "config_parameters" and "target_config_overrides" in a given dictionary
216241 # data: the configuration data of the library/appliation
217242 # params: storage for the discovered configuration parameters
218243 # unit_name: the unit (library/application) that defines this parameter
219244 # unit_kind: the kind of the unit ("library" or "application")
220245 def _process_config_and_overrides (self , data , params , unit_name , unit_kind ):
246+ self .config_errors = []
221247 self ._process_config_parameters (data .get ("config" , {}), params , unit_name , unit_kind )
222248 for label , overrides in data .get ("target_overrides" , {}).items ():
223249 # If the label is defined by the target or it has the special value "*", process the overrides
224250 if (label == '*' ) or (label in self .target_labels ):
225- # Parse out cumulative attributes
226- for attr in Target ._Target__cumulative_attributes :
227- attrs = getattr (self .target_instance , attr )
228-
229- if attr in overrides :
230- del attrs [:]
231- attrs .extend (overrides [attr ])
232- del overrides [attr ]
233-
234- if attr + '_add' in overrides :
235- attrs .extend (overrides [attr + '_add' ])
236- del overrides [attr + '_add' ]
237-
238- if attr + '_remove' in overrides :
239- for a in overrides [attr + '_remove' ]:
240- attrs .remove (a )
241- del overrides [attr + '_remove' ]
242-
243- setattr (self .target_instance , attr , attrs )
251+ # Parse out features
252+ if 'target.features' in overrides :
253+ features = overrides ['target.features' ]
254+ self .remove_features (self .added_features - set (features ))
255+ self .add_features (features )
256+ self .removed_unecessary_features = True
257+ del overrides ['target.features' ]
258+
259+ if 'target.features_add' in overrides :
260+ self .add_features (overrides ['target.features_add' ])
261+ del overrides ['target.features_add' ]
262+
263+ if 'target.features_remove' in overrides :
264+ self .remove_features (overrides ['target.features_remove' ])
265+ del overrides ['target.features_remove' ]
244266
245267 # Consider the others as overrides
246268 for name , v in overrides .items ():
247269 # Get the full name of the parameter
248270 full_name = ConfigParameter .get_full_name (name , unit_name , unit_kind , label )
249- # If an attempt is made to override a parameter that isn't defined, raise an error
250- if not full_name in params :
251- raise ConfigException ("Attempt to override undefined parameter '%s' in '%s'" % (full_name , ConfigParameter .get_display_name (unit_name , unit_kind , label )))
252- params [full_name ].set_value (v , unit_name , unit_kind , label )
271+ if full_name in params :
272+ params [full_name ].set_value (v , unit_name , unit_kind , label )
273+ else :
274+ self .config_errors .append (ConfigException ("Attempt to override undefined parameter '%s' in '%s'"
275+ % (full_name , ConfigParameter .get_display_name (unit_name , unit_kind , label ))))
253276 return params
254277
255278 # Read and interpret configuration data defined by targets
@@ -345,3 +368,23 @@ def get_config_data_macros(self):
345368 params , macros = self .get_config_data ()
346369 self ._check_required_parameters (params )
347370 return macros + self .parameters_to_macros (params )
371+
372+ # Returns any features in the configuration data
373+ def get_features (self ):
374+ params , _ = self .get_config_data ()
375+ self ._check_required_parameters (params )
376+ features = ((set (Target .get_target (self .target ).features )
377+ | self .added_features ) - self .removed_features )
378+
379+ for feature in features :
380+ if feature not in self .__allowed_features :
381+ raise ConfigException ("Feature '%s' is not a supported features" % feature )
382+
383+ return features
384+
385+ # Validate configuration settings. This either returns True or raises an exception
386+ def validate_config (self ):
387+ if self .config_errors :
388+ raise self .config_errors [0 ]
389+ return True
390+
0 commit comments