@@ -137,6 +137,41 @@ def __init__(self, name, unit_name, unit_kind):
137137 self .macro_name = name
138138 self .macro_value = None
139139
140+ # Representation of overrides for cumulative attributes
141+ class ConfigCumulativeOverride :
142+ def __init__ (self , name , additions = set (), removals = set (), strict = False ):
143+ self .name = name
144+ self .additions = set (additions )
145+ self .removals = set (removals )
146+ self .strict = strict
147+
148+ # Add attr to the cumulative override
149+ def remove_cumulative_overrides (self , overrides ):
150+ for override in overrides :
151+ if override in self .additions :
152+ raise ConfigException ("Configuration conflict. The %s %s both added and removed." % (self .name [:- 1 ], override ))
153+
154+ self .removals |= set (overrides )
155+
156+ # Remove attr from the cumulative overrides
157+ def add_cumulative_overrides (self , overrides ):
158+ for override in overrides :
159+ if (override in self .removals or (self .strict and override not in self .additions )):
160+ raise ConfigException ("Configuration conflict. The %s %s both added and removed." % (self .name [:- 1 ], override ))
161+
162+ self .additions |= set (overrides )
163+
164+ # Enable strict set of cumulative overrides for the specified attr
165+ def strict_cumulative_overrides (self , overrides ):
166+ self .remove_cumulative_overrides (self .additions - set (overrides ))
167+ self .add_cumulative_overrides (overrides )
168+ self .strict = True
169+
170+ def update_target (self , target ):
171+ setattr (target , self .name , list (
172+ set (getattr (target , self .name , [])) | self .additions - self .removals ))
173+
174+
140175# 'Config' implements the mbed configuration mechanism
141176class Config :
142177 # Libraries and applications have different names for their configuration files
@@ -184,9 +219,12 @@ def __init__(self, target, top_level_dirs = []):
184219 self .processed_configs = {}
185220 self .target = target if isinstance (target , basestring ) else target .name
186221 self .target_labels = Target .get_target (self .target ).get_labels ()
187- self .added_features = set ()
188- self .removed_features = set ()
189- self .removed_unecessary_features = False
222+
223+ self .cumulative_overrides = { key : ConfigCumulativeOverride (key )
224+ for key in Target ._Target__cumulative_attributes }
225+
226+ self ._process_config_and_overrides (self .app_config_data , {}, "app" , "application" )
227+ self .target_labels = Target .get_target (self .target ).get_labels ()
190228
191229 # Add one or more configuration files
192230 def add_config_files (self , flist ):
@@ -222,23 +260,6 @@ def _process_config_parameters(self, data, params, unit_name, unit_kind):
222260 params [full_name ] = ConfigParameter (name , v if isinstance (v , dict ) else {"value" : v }, unit_name , unit_kind )
223261 return params
224262
225- # Add features to the available features
226- def remove_features (self , features ):
227- for feature in features :
228- if feature in self .added_features :
229- raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
230-
231- self .removed_features |= set (features )
232-
233- # Remove features from the available features
234- def add_features (self , features ):
235- for feature in features :
236- if (feature in self .removed_features
237- or (self .removed_unecessary_features and feature not in self .added_features )):
238- raise ConfigException ("Configuration conflict. Feature %s both added and removed." % feature )
239-
240- self .added_features |= set (features )
241-
242263 # Helper function: process "config_parameters" and "target_config_overrides" in a given dictionary
243264 # data: the configuration data of the library/appliation
244265 # params: storage for the discovered configuration parameters
@@ -250,21 +271,25 @@ def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
250271 for label , overrides in data .get ("target_overrides" , {}).items ():
251272 # If the label is defined by the target or it has the special value "*", process the overrides
252273 if (label == '*' ) or (label in self .target_labels ):
253- # Parse out features
254- if 'target.features' in overrides :
255- features = overrides ['target.features' ]
256- self .remove_features (self .added_features - set (features ))
257- self .add_features (features )
258- self .removed_unecessary_features = True
259- del overrides ['target.features' ]
260-
261- if 'target.features_add' in overrides :
262- self .add_features (overrides ['target.features_add' ])
263- del overrides ['target.features_add' ]
264-
265- if 'target.features_remove' in overrides :
266- self .remove_features (overrides ['target.features_remove' ])
267- del overrides ['target.features_remove' ]
274+ # Check for invalid cumulative overrides in libraries
275+ if (unit_kind == 'library' and
276+ any (attr .startswith ('target.extra_labels' ) for attr in overrides .iterkeys ())):
277+ raise ConfigException ("Target override '%s' in '%s' is only allowed at the application level"
278+ % ("target.extra_labels" , ConfigParameter .get_display_name (unit_name , unit_kind , label )))
279+
280+ # Parse out cumulative overrides
281+ for attr , cumulatives in self .cumulative_overrides .iteritems ():
282+ if 'target.' + attr in overrides :
283+ cumulatives .strict_cumulative_overrides (overrides ['target.' + attr ])
284+ del overrides ['target.' + attr ]
285+
286+ if 'target.' + attr + '_add' in overrides :
287+ cumulatives .add_cumulative_overrides (overrides ['target.' + attr + '_add' ])
288+ del overrides ['target.' + attr + '_add' ]
289+
290+ if 'target.' + attr + '_remove' in overrides :
291+ cumulatives .remove_cumulative_overrides (overrides ['target.' + attr + '_remove' ])
292+ del overrides ['target.' + attr + '_remove' ]
268293
269294 # Consider the others as overrides
270295 for name , v in overrides .items ():
@@ -275,6 +300,10 @@ def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
275300 else :
276301 self .config_errors .append (ConfigException ("Attempt to override undefined parameter '%s' in '%s'"
277302 % (full_name , ConfigParameter .get_display_name (unit_name , unit_kind , label ))))
303+
304+ for cumulatives in self .cumulative_overrides .itervalues ():
305+ cumulatives .update_target (Target .get_target (self .target ))
306+
278307 return params
279308
280309 # Read and interpret configuration data defined by targets
@@ -389,8 +418,8 @@ def get_config_data_macros(self):
389418 def get_features (self ):
390419 params , _ = self .get_config_data ()
391420 self ._check_required_parameters (params )
392- features = (( set ( Target .get_target (self .target ). features )
393- | self . added_features ) - self .removed_features )
421+ self . cumulative_overrides [ ' features' ]. update_target ( Target .get_target (self .target ))
422+ features = Target . get_target ( self .target ). features
394423
395424 for feature in features :
396425 if feature not in self .__allowed_features :
0 commit comments