Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo by
config.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2016 ARM Limited 00004 00005 Licensed under the Apache License, Version 2.0 (the "License"); 00006 you may not use this file except in compliance with the License. 00007 You may obtain a copy of the License at 00008 00009 http://www.apache.org/licenses/LICENSE-2.0 00010 00011 Unless required by applicable law or agreed to in writing, software 00012 distributed under the License is distributed on an "AS IS" BASIS, 00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 See the License for the specific language governing permissions and 00015 limitations under the License. 00016 """ 00017 00018 import os 00019 import sys 00020 00021 # Implementation of mbed configuration mechanism 00022 from tools.utils import json_file_to_dict 00023 from tools.targets import Target 00024 00025 # Base class for all configuration exceptions 00026 class ConfigException (Exception): 00027 """Config system only exception. Makes it easier to distinguish config 00028 errors""" 00029 pass 00030 00031 class ConfigParameter (object): 00032 """This class keeps information about a single configuration parameter""" 00033 00034 def __init__ (self, name, data, unit_name, unit_kind): 00035 """Construct a ConfigParameter 00036 00037 Positional arguments: 00038 name - the name of the configuration parameter 00039 data - the data associated with the configuration parameter 00040 unit_name - the unit (target/library/application) that defines this 00041 parameter 00042 unit_ kind - the kind of the unit ("target", "library" or "application") 00043 """ 00044 self.name = self.get_full_name (name, unit_name, unit_kind, 00045 allow_prefix=False) 00046 self.defined_by = self.get_display_name (unit_name, unit_kind) 00047 self.set_value (data.get("value", None), unit_name, unit_kind) 00048 self.help_text = data.get("help", None) 00049 self.required = data.get("required", False) 00050 self.macro_name = data.get("macro_name", "MBED_CONF_%s" % 00051 self.sanitize (self.name .upper())) 00052 self.config_errors = [] 00053 00054 @staticmethod 00055 def get_full_name (name, unit_name, unit_kind, label=None, 00056 allow_prefix=True): 00057 """Return the full (prefixed) name of a parameter. If the parameter 00058 already has a prefix, check if it is valid 00059 00060 Positional arguments: 00061 name - the simple (unqualified) name of the parameter 00062 unit_name - the unit (target/library/application) that defines this 00063 parameter 00064 unit_kind - the kind of the unit ("target", "library" or "application") 00065 00066 Keyword arguments: 00067 label - the name of the label in the 'target_config_overrides' section 00068 allow_prefix - True to allow the original name to have a prefix, False 00069 otherwise 00070 """ 00071 if name.find('.') == -1: # the name is not prefixed 00072 if unit_kind == "target": 00073 prefix = "target." 00074 elif unit_kind == "application": 00075 prefix = "app." 00076 else: 00077 prefix = unit_name + '.' 00078 return prefix + name 00079 # The name has a prefix, so check if it is valid 00080 if not allow_prefix: 00081 raise ConfigException("Invalid parameter name '%s' in '%s'" % 00082 (name, ConfigParameter.get_display_name( 00083 unit_name, unit_kind, label))) 00084 temp = name.split(".") 00085 # Check if the parameter syntax is correct (must be 00086 # unit_name.parameter_name) 00087 if len(temp) != 2: 00088 raise ConfigException("Invalid parameter name '%s' in '%s'" % 00089 (name, ConfigParameter.get_display_name( 00090 unit_name, unit_kind, label))) 00091 prefix = temp[0] 00092 # Check if the given parameter prefix matches the expected prefix 00093 if (unit_kind == "library" and prefix != unit_name) or \ 00094 (unit_kind == "target" and prefix != "target"): 00095 raise ConfigException( 00096 "Invalid prefix '%s' for parameter name '%s' in '%s'" % 00097 (prefix, name, ConfigParameter.get_display_name( 00098 unit_name, unit_kind, label))) 00099 return name 00100 00101 @staticmethod 00102 def get_display_name (unit_name, unit_kind, label=None): 00103 """Return the name displayed for a unit when interrogating the origin 00104 and the last set place of a parameter 00105 00106 Positional arguments: 00107 unit_name - the unit (target/library/application) that defines this 00108 parameter 00109 unit_kind - the kind of the unit ("target", "library" or "application") 00110 00111 Keyword arguments: 00112 label - the name of the label in the 'target_config_overrides' section 00113 """ 00114 if unit_kind == "target": 00115 return "target:" + unit_name 00116 elif unit_kind == "application": 00117 return "application%s" % ("[%s]" % label if label else "") 00118 else: # library 00119 return "library:%s%s" % (unit_name, "[%s]" % label if label else "") 00120 00121 @staticmethod 00122 def sanitize (name): 00123 """ "Sanitize" a name so that it is a valid C macro name. Currently it 00124 simply replaces '.' and '-' with '_'. 00125 00126 Positional arguments: 00127 name - the name to make into a valid C macro 00128 """ 00129 return name.replace('.', '_').replace('-', '_') 00130 00131 def set_value (self, value, unit_name, unit_kind, label=None): 00132 """ Sets a value for this parameter, remember the place where it was 00133 set. If the value is a Boolean, it is converted to 1 (for True) or 00134 to 0 (for False). 00135 00136 Positional arguments: 00137 value - the value of the parameter 00138 unit_name - the unit (target/library/application) that defines this 00139 parameter 00140 unit_kind - the kind of the unit ("target", "library" or "application") 00141 00142 Keyword arguments: 00143 label - the name of the label in the 'target_config_overrides' section 00144 (optional) 00145 """ 00146 self.value = int(value) if isinstance(value, bool) else value 00147 self.set_by = self.get_display_name (unit_name, unit_kind, label) 00148 00149 def __str__ (self): 00150 """Return the string representation of this configuration parameter 00151 00152 Arguments: None 00153 """ 00154 if self.value is not None: 00155 return '%s = %s (macro name: "%s")' % \ 00156 (self.name , self.value , self.macro_name ) 00157 else: 00158 return '%s has no value' % self.name 00159 00160 def get_verbose_description (self): 00161 """Return a verbose description of this configuration parameter as a 00162 string 00163 00164 Arguments: None 00165 """ 00166 desc = "Name: %s%s\n" % \ 00167 (self.name , " (required parameter)" if self.required else "") 00168 if self.help_text : 00169 desc += " Description: %s\n" % self.help_text 00170 desc += " Defined by: %s\n" % self.defined_by 00171 if not self.value : 00172 return desc + " No value set" 00173 desc += " Macro name: %s\n" % self.macro_name 00174 desc += " Value: %s (set by %s)" % (self.value , self.set_by ) 00175 return desc 00176 00177 class ConfigMacro (object): 00178 """ A representation of a configuration macro. It handles both macros 00179 without a value (MACRO) and with a value (MACRO=VALUE) 00180 """ 00181 def __init__ (self, name, unit_name, unit_kind): 00182 """Construct a ConfigMacro object 00183 00184 Positional arguments: 00185 name - the macro's name 00186 unit_name - the location where the macro was defined 00187 unit_kind - the type of macro this is 00188 """ 00189 self.name = name 00190 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind) 00191 if name.find("=") != -1: 00192 tmp = name.split("=") 00193 if len(tmp) != 2: 00194 raise ValueError("Invalid macro definition '%s' in '%s'" % 00195 (name, self.defined_by )) 00196 self.macro_name = tmp[0] 00197 self.macro_value = tmp[1] 00198 else: 00199 self.macro_name = name 00200 self.macro_value = None 00201 00202 class ConfigCumulativeOverride (object): 00203 """Representation of overrides for cumulative attributes""" 00204 def __init__ (self, name, additions=None, removals=None, strict=False): 00205 """Construct a ConfigCumulativeOverride object 00206 00207 Positional arguments: 00208 name - the name of the config file this came from ? 00209 00210 Keyword arguments: 00211 additions - macros to add to the overrides 00212 removals - macros to remove from the overrides 00213 strict - Boolean indicating that attempting to remove from an override 00214 that does not exist should error 00215 """ 00216 self.name = name 00217 if additions: 00218 self.additions = set(additions) 00219 else: 00220 self.additions = set() 00221 if removals: 00222 self.removals = set(removals) 00223 else: 00224 self.removals = set() 00225 self.strict = strict 00226 00227 def remove_cumulative_overrides (self, overrides): 00228 """Extend the list of override removals. 00229 00230 Positional arguments: 00231 overrides - a list of names that, when the override is evaluated, will 00232 be removed 00233 """ 00234 for override in overrides: 00235 if override in self.additions : 00236 raise ConfigException( 00237 "Configuration conflict. The %s %s both added and removed." 00238 % (self.name [:-1], override)) 00239 00240 self.removals |= set(overrides) 00241 00242 def add_cumulative_overrides (self, overrides): 00243 """Extend the list of override additions. 00244 00245 Positional arguments: 00246 overrides - a list of a names that, when the override is evaluated, will 00247 be added to the list 00248 """ 00249 for override in overrides: 00250 if override in self.removals or \ 00251 (self.strict and override not in self.additions ): 00252 raise ConfigException( 00253 "Configuration conflict. The %s %s both added and removed." 00254 % (self.name [:-1], override)) 00255 00256 self.additions |= set(overrides) 00257 00258 def strict_cumulative_overrides (self, overrides): 00259 """Remove all overrides that are not the specified ones 00260 00261 Positional arguments: 00262 overrides - a list of names that will replace the entire attribute when 00263 this override is evaluated. 00264 """ 00265 self.remove_cumulative_overrides (self.additions - set(overrides)) 00266 self.add_cumulative_overrides (overrides) 00267 self.strict = True 00268 00269 def update_target (self, target): 00270 """Update the attributes of a target based on this override""" 00271 setattr(target, self.name , 00272 list((set(getattr(target, self.name , [])) 00273 | self.additions ) - self.removals )) 00274 00275 00276 def _process_config_parameters(data, params, unit_name, unit_kind): 00277 """Process a "config_parameters" section in either a target, a library, 00278 or the application. 00279 00280 Positional arguments: 00281 data - a dictionary with the configuration parameters 00282 params - storage for the discovered configuration parameters 00283 unit_name - the unit (target/library/application) that defines this 00284 parameter 00285 unit_kind - the kind of the unit ("target", "library" or "application") 00286 """ 00287 for name, val in data.items(): 00288 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind) 00289 # If the parameter was already defined, raise an error 00290 if full_name in params: 00291 raise ConfigException( 00292 "Parameter name '%s' defined in both '%s' and '%s'" % 00293 (name, ConfigParameter.get_display_name(unit_name, unit_kind), 00294 params[full_name].defined_by)) 00295 # Otherwise add it to the list of known parameters 00296 # If "val" is not a dictionary, this is a shortcut definition, 00297 # otherwise it is a full definition 00298 params[full_name] = ConfigParameter(name, val if isinstance(val, dict) 00299 else {"value": val}, unit_name, 00300 unit_kind) 00301 return params 00302 00303 00304 def _process_macros(mlist, macros, unit_name, unit_kind): 00305 """Process a macro definition and check for incompatible duplicate 00306 definitions. 00307 00308 Positional arguments: 00309 mlist - list of macro names to process 00310 macros - dictionary with currently discovered macros 00311 unit_name - the unit (library/application) that defines this macro 00312 unit_kind - the kind of the unit ("library" or "application") 00313 """ 00314 for mname in mlist: 00315 macro = ConfigMacro(mname, unit_name, unit_kind) 00316 if (macro.macro_name in macros) and \ 00317 (macros[macro.macro_name].name != mname): 00318 # Found an incompatible definition of the macro in another module, 00319 # so raise an error 00320 full_unit_name = ConfigParameter.get_display_name(unit_name, 00321 unit_kind) 00322 raise ConfigException( 00323 ("Macro '%s' defined in both '%s' and '%s'" 00324 % (macro.macro_name, macros[macro.macro_name].defined_by, 00325 full_unit_name)) + 00326 " with incompatible values") 00327 macros[macro.macro_name] = macro 00328 00329 00330 class Config (object): 00331 """'Config' implements the mbed configuration mechanism""" 00332 00333 # Libraries and applications have different names for their configuration 00334 # files 00335 __mbed_app_config_name = "mbed_app.json" 00336 __mbed_lib_config_name = "mbed_lib.json" 00337 00338 # Allowed keys in configuration dictionaries 00339 # (targets can have any kind of keys, so this validation is not applicable 00340 # to them) 00341 __allowed_keys = { 00342 "library": set(["name", "config", "target_overrides", "macros", 00343 "__config_path"]), 00344 "application": set(["config", "custom_targets", "target_overrides", 00345 "macros", "__config_path"]) 00346 } 00347 00348 # Allowed features in configurations 00349 __allowed_features = [ 00350 "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL", "STORAGE" 00351 ] 00352 00353 def __init__ (self, target, top_level_dirs=None, app_config=None): 00354 """Construct a mbed configuration 00355 00356 Positional arguments: 00357 target - the name of the mbed target used for this configuration 00358 instance 00359 00360 Keyword argumets: 00361 top_level_dirs - a list of top level source directories (where 00362 mbed_app_config.json could be found) 00363 app_config - location of a chosen mbed_app.json file 00364 00365 NOTE: Construction of a Config object will look for the application 00366 configuration file in top_level_dirs. If found once, it'll parse it and 00367 check if it has a custom_targets function. If it does, it'll update the 00368 list of targets as needed. If more than one config file is found, an 00369 exception is raised. top_level_dirs may be None (in this case, 00370 the constructor will not search for a configuration file) 00371 """ 00372 app_config_location = app_config 00373 if app_config_location is None: 00374 for directory in top_level_dirs or []: 00375 full_path = os.path.join(directory, self.__mbed_app_config_name ) 00376 if os.path.isfile(full_path): 00377 if app_config_location is not None: 00378 raise ConfigException("Duplicate '%s' file in '%s' and '%s'" 00379 % (self.__mbed_app_config_name , 00380 app_config_location, full_path)) 00381 else: 00382 app_config_location = full_path 00383 try: 00384 self.app_config_data = json_file_to_dict(app_config_location) \ 00385 if app_config_location else {} 00386 except ValueError as exc: 00387 sys.stderr.write(str(exc) + "\n") 00388 self.app_config_data = {} 00389 00390 # Check the keys in the application configuration data 00391 unknown_keys = set(self.app_config_data .keys()) - \ 00392 self.__allowed_keys ["application"] 00393 if unknown_keys: 00394 raise ConfigException("Unknown key(s) '%s' in %s" % 00395 (",".join(unknown_keys), 00396 self.__mbed_app_config_name )) 00397 # Update the list of targets with the ones defined in the application 00398 # config, if applicable 00399 Target.add_py_targets(self.app_config_data .get("custom_targets", {})) 00400 self.lib_config_data = {} 00401 # Make sure that each config is processed only once 00402 self.processed_configs = {} 00403 self.target = target if isinstance(target, basestring) else target.name 00404 self.target_labels = Target.get_target(self.target ).get_labels() 00405 00406 self.cumulative_overrides = {key: ConfigCumulativeOverride(key) 00407 for key in 00408 Target.cumulative_attributes} 00409 00410 self._process_config_and_overrides (self.app_config_data , {}, "app", 00411 "application") 00412 self.target_labels = Target.get_target(self.target ).get_labels() 00413 self.config_errors = None 00414 00415 def add_config_files (self, flist): 00416 """Add configuration files 00417 00418 Positional arguments: 00419 flist - a list of files to add to this configuration 00420 """ 00421 for config_file in flist: 00422 if not config_file.endswith(self.__mbed_lib_config_name ): 00423 continue 00424 full_path = os.path.normpath(os.path.abspath(config_file)) 00425 # Check that we didn't already process this file 00426 if self.processed_configs .has_key(full_path): 00427 continue 00428 self.processed_configs [full_path] = True 00429 # Read the library configuration and add a "__full_config_path" 00430 # attribute to it 00431 try: 00432 cfg = json_file_to_dict(config_file) 00433 except ValueError as exc: 00434 sys.stderr.write(str(exc) + "\n") 00435 continue 00436 00437 cfg["__config_path"] = full_path 00438 00439 if "name" not in cfg: 00440 raise ConfigException( 00441 "Library configured at %s has no name field." % full_path) 00442 # If there's already a configuration for a module with the same 00443 # name, exit with error 00444 if self.lib_config_data .has_key(cfg["name"]): 00445 raise ConfigException( 00446 "Library name '%s' is not unique (defined in '%s' and '%s')" 00447 % (cfg["name"], full_path, 00448 self.lib_config_data [cfg["name"]]["__config_path"])) 00449 self.lib_config_data [cfg["name"]] = cfg 00450 00451 00452 def _process_config_and_overrides(self, data, params, unit_name, unit_kind): 00453 """Process "config_parameters" and "target_config_overrides" into a 00454 given dictionary 00455 00456 Positional arguments: 00457 data - the configuration data of the library/appliation 00458 params - storage for the discovered configuration parameters 00459 unit_name - the unit (library/application) that defines this parameter 00460 unit_kind - the kind of the unit ("library" or "application") 00461 """ 00462 self.config_errors = [] 00463 _process_config_parameters(data.get("config", {}), params, unit_name, 00464 unit_kind) 00465 for label, overrides in data.get("target_overrides", {}).items(): 00466 # If the label is defined by the target or it has the special value 00467 # "*", process the overrides 00468 if (label == '*') or (label in self.target_labels ): 00469 # Check for invalid cumulative overrides in libraries 00470 if (unit_kind == 'library' and 00471 any(attr.startswith('target.extra_labels') for attr 00472 in overrides.iterkeys())): 00473 raise ConfigException( 00474 "Target override 'target.extra_labels' in " + 00475 ConfigParameter.get_display_name(unit_name, unit_kind, 00476 label) + 00477 " is only allowed at the application level") 00478 00479 # Parse out cumulative overrides 00480 for attr, cumulatives in self.cumulative_overrides .iteritems(): 00481 if 'target.'+attr in overrides: 00482 cumulatives.strict_cumulative_overrides( 00483 overrides['target.'+attr]) 00484 del overrides['target.'+attr] 00485 00486 if 'target.'+attr+'_add' in overrides: 00487 cumulatives.add_cumulative_overrides( 00488 overrides['target.'+attr+'_add']) 00489 del overrides['target.'+attr+'_add'] 00490 00491 if 'target.'+attr+'_remove' in overrides: 00492 cumulatives.remove_cumulative_overrides( 00493 overrides['target.'+attr+'_remove']) 00494 del overrides['target.'+attr+'_remove'] 00495 00496 # Consider the others as overrides 00497 for name, val in overrides.items(): 00498 # Get the full name of the parameter 00499 full_name = ConfigParameter.get_full_name(name, unit_name, 00500 unit_kind, label) 00501 if full_name in params: 00502 params[full_name].set_value(val, unit_name, unit_kind, 00503 label) 00504 else: 00505 self.config_errors .append( 00506 ConfigException( 00507 "Attempt to override undefined parameter" + 00508 (" '%s' in '%s'" 00509 % (full_name, 00510 ConfigParameter.get_display_name(unit_name, 00511 unit_kind, 00512 label))))) 00513 00514 for cumulatives in self.cumulative_overrides .itervalues(): 00515 cumulatives.update_target(Target.get_target(self.target )) 00516 00517 return params 00518 00519 def get_target_config_data (self): 00520 """Read and interpret configuration data defined by targets. 00521 00522 We consider the resolution order for our target and sort it by level 00523 reversed, so that we first look at the top level target (the parent), 00524 then its direct children, then the children of those children and so on, 00525 until we reach self.target 00526 TODO: this might not work so well in some multiple inheritance scenarios 00527 At each step, look at two keys of the target data: 00528 - config_parameters: used to define new configuration parameters 00529 - config_overrides: used to override already defined configuration 00530 parameters 00531 00532 Arguments: None 00533 """ 00534 params, json_data = {}, Target.get_json_target_data() 00535 resolution_order = [e[0] for e 00536 in sorted( 00537 Target.get_target(self.target ).resolution_order, 00538 key=lambda e: e[1], reverse=True)] 00539 for tname in resolution_order: 00540 # Read the target data directly from its description 00541 target_data = json_data[tname] 00542 # Process definitions first 00543 _process_config_parameters(target_data.get("config", {}), params, 00544 tname, "target") 00545 # Then process overrides 00546 for name, val in target_data.get("overrides", {}).items(): 00547 full_name = ConfigParameter.get_full_name(name, tname, "target") 00548 # If the parameter name is not defined or if there isn't a path 00549 # from this target to the target where the parameter was defined 00550 # in the target inheritance tree, raise an error We need to use 00551 # 'defined_by[7:]' to remove the "target:" prefix from 00552 # defined_by 00553 if (full_name not in params) or \ 00554 (params[full_name].defined_by[7:] not in 00555 Target.get_target(tname).resolution_order_names): 00556 raise ConfigException( 00557 "Attempt to override undefined parameter '%s' in '%s'" 00558 % (name, 00559 ConfigParameter.get_display_name(tname, "target"))) 00560 # Otherwise update the value of the parameter 00561 params[full_name].set_value(val, tname, "target") 00562 return params 00563 00564 def get_lib_config_data (self): 00565 """ Read and interpret configuration data defined by libraries. It is 00566 assumed that "add_config_files" above was already called and the library 00567 configuration data exists in self.lib_config_data 00568 00569 Arguments: None 00570 """ 00571 all_params, macros = {}, {} 00572 for lib_name, lib_data in self.lib_config_data .items(): 00573 unknown_keys = set(lib_data.keys()) - self.__allowed_keys ["library"] 00574 if unknown_keys: 00575 raise ConfigException("Unknown key(s) '%s' in %s" % 00576 (",".join(unknown_keys), lib_name)) 00577 all_params.update(self._process_config_and_overrides (lib_data, {}, 00578 lib_name, 00579 "library")) 00580 _process_macros(lib_data.get("macros", []), macros, lib_name, 00581 "library") 00582 return all_params, macros 00583 00584 def get_app_config_data (self, params, macros): 00585 """ Read and interpret the configuration data defined by the target. The 00586 target can override any configuration parameter, as well as define its 00587 own configuration data. 00588 00589 Positional arguments. 00590 params - the dictionary with configuration parameters found so far (in 00591 the target and in libraries) 00592 macros - the list of macros defined in the configuration 00593 """ 00594 app_cfg = self.app_config_data 00595 # The application can have a "config_parameters" and a 00596 # "target_config_overrides" section just like a library 00597 self._process_config_and_overrides (app_cfg, params, "app", 00598 "application") 00599 # The application can also defined macros 00600 _process_macros(app_cfg.get("macros", []), macros, "app", 00601 "application") 00602 00603 def get_config_data (self): 00604 """ Return the configuration data in two parts: (params, macros) 00605 params - a dictionary with mapping a name to a ConfigParam 00606 macros - the list of macros defined with "macros" in libraries and in 00607 the application (as ConfigMacro instances) 00608 00609 Arguments: None 00610 """ 00611 all_params = self.get_target_config_data () 00612 lib_params, macros = self.get_lib_config_data () 00613 all_params.update(lib_params) 00614 self.get_app_config_data (all_params, macros) 00615 return all_params, macros 00616 00617 @staticmethod 00618 def _check_required_parameters(params): 00619 """Check that there are no required parameters without a value 00620 00621 Positional arguments: 00622 params - the list of parameters to check 00623 00624 NOTE: This function does not return. Instead, it throws a 00625 ConfigException when any of the required parameters are missing values 00626 """ 00627 for param in params.values(): 00628 if param.required and (param.value is None): 00629 raise ConfigException("Required parameter '" + param.name + 00630 "' defined by '" + param.defined_by + 00631 "' doesn't have a value") 00632 00633 @staticmethod 00634 def parameters_to_macros (params): 00635 """ Encode the configuration parameters as C macro definitions. 00636 00637 Positional arguments: 00638 params - a dictionary mapping a name to a ConfigParameter 00639 00640 Return: a list of strings that encode the configuration parameters as 00641 C pre-processor macros 00642 """ 00643 return ['%s=%s' % (m.macro_name, m.value) for m in params.values() 00644 if m.value is not None] 00645 00646 @staticmethod 00647 def config_macros_to_macros (macros): 00648 """ Return the macro definitions generated for a dictionary of 00649 ConfigMacros (as returned by get_config_data). 00650 00651 Positional arguments: 00652 params - a dictionary mapping a name to a ConfigMacro instance 00653 00654 Return: a list of strings that are the C pre-processor macros 00655 """ 00656 return [m.name for m in macros.values()] 00657 00658 @staticmethod 00659 def config_to_macros (config): 00660 """Convert the configuration data to a list of C macros 00661 00662 Positional arguments: 00663 config - configuration data as (ConfigParam instances, ConfigMacro 00664 instances) tuple (as returned by get_config_data()) 00665 """ 00666 params, macros = config[0], config[1] 00667 Config._check_required_parameters(params) 00668 return Config.config_macros_to_macros(macros) + \ 00669 Config.parameters_to_macros(params) 00670 00671 def get_config_data_macros (self): 00672 """ Convert a Config object to a list of C macros 00673 00674 Arguments: None 00675 """ 00676 return self.config_to_macros (self.get_config_data ()) 00677 00678 def get_features (self): 00679 """ Extract any features from the configuration data 00680 00681 Arguments: None 00682 """ 00683 params, _ = self.get_config_data () 00684 self._check_required_parameters (params) 00685 self.cumulative_overrides ['features']\ 00686 .update_target(Target.get_target(self.target )) 00687 features = Target.get_target(self.target ).features 00688 00689 for feature in features: 00690 if feature not in self.__allowed_features : 00691 raise ConfigException( 00692 "Feature '%s' is not a supported features" % feature) 00693 00694 return features 00695 00696 def validate_config (self): 00697 """ Validate configuration settings. This either returns True or 00698 raises an exception 00699 00700 Arguments: None 00701 """ 00702 if self.config_errors : 00703 raise self.config_errors [0] 00704 return True 00705 00706 00707 def load_resources (self, resources): 00708 """ Load configuration data from a Resources instance and expand it 00709 based on defined features. 00710 00711 Positional arguments: 00712 resources - the resources object to load from and expand 00713 """ 00714 # Update configuration files until added features creates no changes 00715 prev_features = set() 00716 while True: 00717 # Add/update the configuration with any .json files found while 00718 # scanning 00719 self.add_config_files (resources.json_files) 00720 00721 # Add features while we find new ones 00722 features = set(self.get_features ()) 00723 if features == prev_features: 00724 break 00725 00726 for feature in features: 00727 if feature in resources.features: 00728 resources.add(resources.features[feature]) 00729 00730 prev_features = features 00731 self.validate_config () 00732 00733 return resources 00734 00735 @staticmethod 00736 def config_to_header (config, fname=None): 00737 """ Convert the configuration data to the content of a C header file, 00738 meant to be included to a C/C++ file. The content is returned as a 00739 string. 00740 00741 Positional arguments: 00742 config - configuration data as (ConfigParam instances, ConfigMacro 00743 instances) tuple (as returned by get_config_data()) 00744 00745 Keyword arguments: 00746 fname - also write the content is to the file called "fname". 00747 WARNING: if 'fname' names an existing file, it will be 00748 overwritten! 00749 """ 00750 params, macros = config[0], config[1] 00751 Config._check_required_parameters(params) 00752 header_data = "// Automatically generated configuration file.\n" 00753 header_data += "// DO NOT EDIT, content will be overwritten.\n\n" 00754 header_data += "#ifndef __MBED_CONFIG_DATA__\n" 00755 header_data += "#define __MBED_CONFIG_DATA__\n\n" 00756 # Compute maximum length of macro names for proper alignment 00757 max_param_macro_name_len = (max([len(m.macro_name) for m 00758 in params.values() 00759 if m.value is not None]) 00760 if params else 0) 00761 max_direct_macro_name_len = (max([len(m.macro_name) for m 00762 in macros.values()]) 00763 if macros else 0) 00764 max_macro_name_len = max(max_param_macro_name_len, 00765 max_direct_macro_name_len) 00766 # Compute maximum length of macro values for proper alignment 00767 max_param_macro_val_len = (max([len(str(m.value)) for m 00768 in params.values() 00769 if m.value is not None]) 00770 if params else 0) 00771 max_direct_macro_val_len = max([len(m.macro_value or "") for m 00772 in macros.values()]) if macros else 0 00773 max_macro_val_len = max(max_param_macro_val_len, 00774 max_direct_macro_val_len) 00775 # Generate config parameters first 00776 if params: 00777 header_data += "// Configuration parameters\n" 00778 for macro in params.values(): 00779 if macro.value is not None: 00780 header_data += ("#define {0:<{1}} {2!s:<{3}} " + 00781 "// set by {4}\n")\ 00782 .format(macro.macro_name, max_macro_name_len, 00783 macro.value, max_macro_val_len, macro.set_by) 00784 # Then macros 00785 if macros: 00786 header_data += "// Macros\n" 00787 for macro in macros.values(): 00788 if macro.macro_value: 00789 header_data += ("#define {0:<{1}} {2!s:<{3}}" + 00790 " // defined by {4}\n")\ 00791 .format(macro.macro_name, max_macro_name_len, 00792 macro.macro_value, max_macro_val_len, 00793 macro.defined_by) 00794 else: 00795 header_data += ("#define {0:<{1}}" + 00796 " // defined by {2}\n")\ 00797 .format(macro.macro_name, 00798 max_macro_name_len + max_macro_val_len + 1, 00799 macro.defined_by) 00800 header_data += "\n#endif\n" 00801 # If fname is given, write "header_data" to it 00802 if fname: 00803 with open(fname, "w+") as file_desc: 00804 file_desc.write(header_data) 00805 return header_data 00806 00807 def get_config_data_header (self, fname=None): 00808 """ Convert a Config instance to the content of a C header file, meant 00809 to be included to a C/C++ file. The content is returned as a string. 00810 00811 Keyword arguments: 00812 fname - also write the content to the file called "fname". 00813 WARNING: if 'fname' names an existing file, it will be 00814 overwritten! 00815 """ 00816 return self.config_to_header (self.get_config_data (), fname)
Generated on Tue Jul 12 2022 12:28:28 by
