the other jimmy / mbed-sdk-tools

Fork of mbed-sdk-tools by mbed official

Committer:
screamer
Date:
Mon Aug 29 11:56:59 2016 +0100
Revision:
30:f12ce67666d0
Parent:
29:1210849dba19
Child:
31:182518299918
Update tools from the mbed OS 5.1.2 release (instead of master)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 8:a8ac6ed29081 1 """
screamer 8:a8ac6ed29081 2 mbed SDK
screamer 8:a8ac6ed29081 3 Copyright (c) 2016 ARM Limited
screamer 8:a8ac6ed29081 4
screamer 8:a8ac6ed29081 5 Licensed under the Apache License, Version 2.0 (the "License");
screamer 8:a8ac6ed29081 6 you may not use this file except in compliance with the License.
screamer 8:a8ac6ed29081 7 You may obtain a copy of the License at
screamer 8:a8ac6ed29081 8
screamer 8:a8ac6ed29081 9 http://www.apache.org/licenses/LICENSE-2.0
screamer 8:a8ac6ed29081 10
screamer 8:a8ac6ed29081 11 Unless required by applicable law or agreed to in writing, software
screamer 8:a8ac6ed29081 12 distributed under the License is distributed on an "AS IS" BASIS,
screamer 8:a8ac6ed29081 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 8:a8ac6ed29081 14 See the License for the specific language governing permissions and
screamer 8:a8ac6ed29081 15 limitations under the License.
screamer 8:a8ac6ed29081 16 """
screamer 8:a8ac6ed29081 17
screamer 8:a8ac6ed29081 18 # Implementation of mbed configuration mechanism
screamer 29:1210849dba19 19 from tools.utils import json_file_to_dict
screamer 8:a8ac6ed29081 20 from tools.targets import Target
screamer 8:a8ac6ed29081 21 import os
screamer 8:a8ac6ed29081 22
screamer 8:a8ac6ed29081 23 # Base class for all configuration exceptions
screamer 8:a8ac6ed29081 24 class ConfigException(Exception):
screamer 29:1210849dba19 25 """Config system only exception. Makes it easier to distinguish config
screamer 29:1210849dba19 26 errors"""
screamer 8:a8ac6ed29081 27 pass
screamer 8:a8ac6ed29081 28
screamer 29:1210849dba19 29 class ConfigParameter(object):
screamer 29:1210849dba19 30 """This class keeps information about a single configuration parameter"""
screamer 29:1210849dba19 31
screamer 8:a8ac6ed29081 32 def __init__(self, name, data, unit_name, unit_kind):
screamer 29:1210849dba19 33 """Construct a ConfigParameter
screamer 29:1210849dba19 34
screamer 29:1210849dba19 35 Positional arguments:
screamer 29:1210849dba19 36 name - the name of the configuration parameter
screamer 29:1210849dba19 37 data - the data associated with the configuration parameter
screamer 29:1210849dba19 38 unit_name - the unit (target/library/application) that defines this
screamer 29:1210849dba19 39 parameter
screamer 29:1210849dba19 40 unit_ kind - the kind of the unit ("target", "library" or "application")
screamer 29:1210849dba19 41 """
screamer 29:1210849dba19 42 self.name = self.get_full_name(name, unit_name, unit_kind,
screamer 29:1210849dba19 43 allow_prefix=False)
screamer 8:a8ac6ed29081 44 self.defined_by = self.get_display_name(unit_name, unit_kind)
screamer 13:ab47a20b66f0 45 self.set_value(data.get("value", None), unit_name, unit_kind)
screamer 8:a8ac6ed29081 46 self.help_text = data.get("help", None)
screamer 8:a8ac6ed29081 47 self.required = data.get("required", False)
screamer 29:1210849dba19 48 self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
screamer 29:1210849dba19 49 self.sanitize(self.name.upper()))
screamer 13:ab47a20b66f0 50 self.config_errors = []
screamer 8:a8ac6ed29081 51
screamer 8:a8ac6ed29081 52 @staticmethod
screamer 29:1210849dba19 53 def get_full_name(name, unit_name, unit_kind, label=None,
screamer 29:1210849dba19 54 allow_prefix=True):
screamer 29:1210849dba19 55 """Return the full (prefixed) name of a parameter. If the parameter
screamer 29:1210849dba19 56 already has a prefix, check if it is valid
screamer 29:1210849dba19 57
screamer 29:1210849dba19 58 Positional arguments:
screamer 29:1210849dba19 59 name - the simple (unqualified) name of the parameter
screamer 29:1210849dba19 60 unit_name - the unit (target/library/application) that defines this
screamer 29:1210849dba19 61 parameter
screamer 29:1210849dba19 62 unit_kind - the kind of the unit ("target", "library" or "application")
screamer 29:1210849dba19 63
screamer 29:1210849dba19 64 Keyword arguments:
screamer 29:1210849dba19 65 label - the name of the label in the 'target_config_overrides' section
screamer 29:1210849dba19 66 allow_prefix - True to allow the original name to have a prefix, False
screamer 29:1210849dba19 67 otherwise
screamer 29:1210849dba19 68 """
screamer 8:a8ac6ed29081 69 if name.find('.') == -1: # the name is not prefixed
screamer 8:a8ac6ed29081 70 if unit_kind == "target":
screamer 8:a8ac6ed29081 71 prefix = "target."
screamer 8:a8ac6ed29081 72 elif unit_kind == "application":
screamer 8:a8ac6ed29081 73 prefix = "app."
screamer 8:a8ac6ed29081 74 else:
screamer 8:a8ac6ed29081 75 prefix = unit_name + '.'
screamer 8:a8ac6ed29081 76 return prefix + name
screamer 8:a8ac6ed29081 77 # The name has a prefix, so check if it is valid
screamer 8:a8ac6ed29081 78 if not allow_prefix:
screamer 29:1210849dba19 79 raise ConfigException("Invalid parameter name '%s' in '%s'" %
screamer 29:1210849dba19 80 (name, ConfigParameter.get_display_name(
screamer 29:1210849dba19 81 unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 82 temp = name.split(".")
screamer 29:1210849dba19 83 # Check if the parameter syntax is correct (must be
screamer 29:1210849dba19 84 # unit_name.parameter_name)
screamer 8:a8ac6ed29081 85 if len(temp) != 2:
screamer 29:1210849dba19 86 raise ConfigException("Invalid parameter name '%s' in '%s'" %
screamer 29:1210849dba19 87 (name, ConfigParameter.get_display_name(
screamer 29:1210849dba19 88 unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 89 prefix = temp[0]
screamer 8:a8ac6ed29081 90 # Check if the given parameter prefix matches the expected prefix
screamer 29:1210849dba19 91 if (unit_kind == "library" and prefix != unit_name) or \
screamer 29:1210849dba19 92 (unit_kind == "target" and prefix != "target"):
screamer 29:1210849dba19 93 raise ConfigException(
screamer 29:1210849dba19 94 "Invalid prefix '%s' for parameter name '%s' in '%s'" %
screamer 29:1210849dba19 95 (prefix, name, ConfigParameter.get_display_name(
screamer 29:1210849dba19 96 unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 97 return name
screamer 8:a8ac6ed29081 98
screamer 8:a8ac6ed29081 99 @staticmethod
screamer 29:1210849dba19 100 def get_display_name(unit_name, unit_kind, label=None):
screamer 29:1210849dba19 101 """Return the name displayed for a unit when interrogating the origin
screamer 29:1210849dba19 102 and the last set place of a parameter
screamer 29:1210849dba19 103
screamer 29:1210849dba19 104 Positional arguments:
screamer 29:1210849dba19 105 unit_name - the unit (target/library/application) that defines this
screamer 29:1210849dba19 106 parameter
screamer 29:1210849dba19 107 unit_kind - the kind of the unit ("target", "library" or "application")
screamer 29:1210849dba19 108
screamer 29:1210849dba19 109 Keyword arguments:
screamer 29:1210849dba19 110 label - the name of the label in the 'target_config_overrides' section
screamer 29:1210849dba19 111 """
screamer 8:a8ac6ed29081 112 if unit_kind == "target":
screamer 8:a8ac6ed29081 113 return "target:" + unit_name
screamer 8:a8ac6ed29081 114 elif unit_kind == "application":
screamer 8:a8ac6ed29081 115 return "application%s" % ("[%s]" % label if label else "")
screamer 8:a8ac6ed29081 116 else: # library
screamer 8:a8ac6ed29081 117 return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
screamer 8:a8ac6ed29081 118
screamer 8:a8ac6ed29081 119 @staticmethod
screamer 8:a8ac6ed29081 120 def sanitize(name):
screamer 29:1210849dba19 121 """ "Sanitize" a name so that it is a valid C macro name. Currently it
screamer 29:1210849dba19 122 simply replaces '.' and '-' with '_'.
screamer 29:1210849dba19 123
screamer 29:1210849dba19 124 Positional arguments:
screamer 29:1210849dba19 125 name - the name to make into a valid C macro
screamer 29:1210849dba19 126 """
screamer 8:a8ac6ed29081 127 return name.replace('.', '_').replace('-', '_')
screamer 8:a8ac6ed29081 128
screamer 29:1210849dba19 129 def set_value(self, value, unit_name, unit_kind, label=None):
screamer 29:1210849dba19 130 """ Sets a value for this parameter, remember the place where it was
screamer 29:1210849dba19 131 set. If the value is a Boolean, it is converted to 1 (for True) or
screamer 29:1210849dba19 132 to 0 (for False).
screamer 29:1210849dba19 133
screamer 29:1210849dba19 134 Positional arguments:
screamer 29:1210849dba19 135 value - the value of the parameter
screamer 29:1210849dba19 136 unit_name - the unit (target/library/application) that defines this
screamer 29:1210849dba19 137 parameter
screamer 29:1210849dba19 138 unit_kind - the kind of the unit ("target", "library" or "application")
screamer 29:1210849dba19 139
screamer 29:1210849dba19 140 Keyword arguments:
screamer 29:1210849dba19 141 label - the name of the label in the 'target_config_overrides' section
screamer 29:1210849dba19 142 (optional)
screamer 29:1210849dba19 143 """
screamer 13:ab47a20b66f0 144 self.value = int(value) if isinstance(value, bool) else value
screamer 8:a8ac6ed29081 145 self.set_by = self.get_display_name(unit_name, unit_kind, label)
screamer 8:a8ac6ed29081 146
screamer 8:a8ac6ed29081 147 def __str__(self):
screamer 29:1210849dba19 148 """Return the string representation of this configuration parameter
screamer 29:1210849dba19 149
screamer 29:1210849dba19 150 Arguments: None
screamer 29:1210849dba19 151 """
screamer 8:a8ac6ed29081 152 if self.value is not None:
screamer 29:1210849dba19 153 return '%s = %s (macro name: "%s")' % \
screamer 29:1210849dba19 154 (self.name, self.value, self.macro_name)
screamer 8:a8ac6ed29081 155 else:
screamer 8:a8ac6ed29081 156 return '%s has no value' % self.name
screamer 8:a8ac6ed29081 157
screamer 8:a8ac6ed29081 158 def get_verbose_description(self):
screamer 29:1210849dba19 159 """Return a verbose description of this configuration parameter as a
screamer 29:1210849dba19 160 string
screamer 29:1210849dba19 161
screamer 29:1210849dba19 162 Arguments: None
screamer 29:1210849dba19 163 """
screamer 29:1210849dba19 164 desc = "Name: %s%s\n" % \
screamer 29:1210849dba19 165 (self.name, " (required parameter)" if self.required else "")
screamer 8:a8ac6ed29081 166 if self.help_text:
screamer 8:a8ac6ed29081 167 desc += " Description: %s\n" % self.help_text
screamer 8:a8ac6ed29081 168 desc += " Defined by: %s\n" % self.defined_by
screamer 8:a8ac6ed29081 169 if not self.value:
screamer 8:a8ac6ed29081 170 return desc + " No value set"
screamer 8:a8ac6ed29081 171 desc += " Macro name: %s\n" % self.macro_name
screamer 8:a8ac6ed29081 172 desc += " Value: %s (set by %s)" % (self.value, self.set_by)
screamer 8:a8ac6ed29081 173 return desc
screamer 8:a8ac6ed29081 174
screamer 29:1210849dba19 175 class ConfigMacro(object):
screamer 29:1210849dba19 176 """ A representation of a configuration macro. It handles both macros
screamer 29:1210849dba19 177 without a value (MACRO) and with a value (MACRO=VALUE)
screamer 29:1210849dba19 178 """
screamer 8:a8ac6ed29081 179 def __init__(self, name, unit_name, unit_kind):
screamer 29:1210849dba19 180 """Construct a ConfigMacro object
screamer 29:1210849dba19 181
screamer 29:1210849dba19 182 Positional arguments:
screamer 29:1210849dba19 183 name - the macro's name
screamer 29:1210849dba19 184 unit_name - the location where the macro was defined
screamer 29:1210849dba19 185 unit_kind - the type of macro this is
screamer 29:1210849dba19 186 """
screamer 8:a8ac6ed29081 187 self.name = name
screamer 8:a8ac6ed29081 188 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
screamer 8:a8ac6ed29081 189 if name.find("=") != -1:
screamer 8:a8ac6ed29081 190 tmp = name.split("=")
screamer 8:a8ac6ed29081 191 if len(tmp) != 2:
screamer 29:1210849dba19 192 raise ValueError("Invalid macro definition '%s' in '%s'" %
screamer 29:1210849dba19 193 (name, self.defined_by))
screamer 8:a8ac6ed29081 194 self.macro_name = tmp[0]
screamer 13:ab47a20b66f0 195 self.macro_value = tmp[1]
screamer 8:a8ac6ed29081 196 else:
screamer 8:a8ac6ed29081 197 self.macro_name = name
screamer 13:ab47a20b66f0 198 self.macro_value = None
screamer 8:a8ac6ed29081 199
screamer 29:1210849dba19 200 class ConfigCumulativeOverride(object):
screamer 29:1210849dba19 201 """Representation of overrides for cumulative attributes"""
screamer 29:1210849dba19 202 def __init__(self, name, additions=None, removals=None, strict=False):
screamer 29:1210849dba19 203 """Construct a ConfigCumulativeOverride object
screamer 29:1210849dba19 204
screamer 29:1210849dba19 205 Positional arguments:
screamer 29:1210849dba19 206 name - the name of the config file this came from ?
screamer 29:1210849dba19 207
screamer 29:1210849dba19 208 Keyword arguments:
screamer 29:1210849dba19 209 additions - macros to add to the overrides
screamer 29:1210849dba19 210 removals - macros to remove from the overrides
screamer 29:1210849dba19 211 strict - Boolean indicating that attempting to remove from an override
screamer 29:1210849dba19 212 that does not exist should error
screamer 29:1210849dba19 213 """
screamer 24:25bff2709c20 214 self.name = name
screamer 29:1210849dba19 215 if additions:
screamer 29:1210849dba19 216 self.additions = set(additions)
screamer 29:1210849dba19 217 else:
screamer 29:1210849dba19 218 self.additions = set()
screamer 29:1210849dba19 219 if removals:
screamer 29:1210849dba19 220 self.removals = set(removals)
screamer 29:1210849dba19 221 else:
screamer 29:1210849dba19 222 self.removals = set()
screamer 24:25bff2709c20 223 self.strict = strict
screamer 24:25bff2709c20 224
screamer 24:25bff2709c20 225 def remove_cumulative_overrides(self, overrides):
screamer 29:1210849dba19 226 """Extend the list of override removals.
screamer 29:1210849dba19 227
screamer 29:1210849dba19 228 Positional arguments:
screamer 29:1210849dba19 229 overrides - a list of names that, when the override is evaluated, will
screamer 29:1210849dba19 230 be removed
screamer 29:1210849dba19 231 """
screamer 24:25bff2709c20 232 for override in overrides:
screamer 24:25bff2709c20 233 if override in self.additions:
screamer 29:1210849dba19 234 raise ConfigException(
screamer 29:1210849dba19 235 "Configuration conflict. The %s %s both added and removed."
screamer 29:1210849dba19 236 % (self.name[:-1], override))
screamer 24:25bff2709c20 237
screamer 24:25bff2709c20 238 self.removals |= set(overrides)
screamer 24:25bff2709c20 239
screamer 24:25bff2709c20 240 def add_cumulative_overrides(self, overrides):
screamer 29:1210849dba19 241 """Extend the list of override additions.
screamer 29:1210849dba19 242
screamer 29:1210849dba19 243 Positional arguments:
screamer 29:1210849dba19 244 overrides - a list of a names that, when the override is evaluated, will
screamer 29:1210849dba19 245 be added to the list
screamer 29:1210849dba19 246 """
screamer 24:25bff2709c20 247 for override in overrides:
screamer 29:1210849dba19 248 if override in self.removals or \
screamer 29:1210849dba19 249 (self.strict and override not in self.additions):
screamer 29:1210849dba19 250 raise ConfigException(
screamer 29:1210849dba19 251 "Configuration conflict. The %s %s both added and removed."
screamer 29:1210849dba19 252 % (self.name[:-1], override))
screamer 24:25bff2709c20 253
screamer 24:25bff2709c20 254 self.additions |= set(overrides)
screamer 24:25bff2709c20 255
screamer 24:25bff2709c20 256 def strict_cumulative_overrides(self, overrides):
screamer 29:1210849dba19 257 """Remove all overrides that are not the specified ones
screamer 29:1210849dba19 258
screamer 29:1210849dba19 259 Positional arguments:
screamer 29:1210849dba19 260 overrides - a list of names that will replace the entire attribute when
screamer 29:1210849dba19 261 this override is evaluated.
screamer 29:1210849dba19 262 """
screamer 24:25bff2709c20 263 self.remove_cumulative_overrides(self.additions - set(overrides))
screamer 24:25bff2709c20 264 self.add_cumulative_overrides(overrides)
screamer 24:25bff2709c20 265 self.strict = True
screamer 24:25bff2709c20 266
screamer 24:25bff2709c20 267 def update_target(self, target):
screamer 29:1210849dba19 268 """Update the attributes of a target based on this override"""
screamer 29:1210849dba19 269 setattr(target, self.name,
screamer 29:1210849dba19 270 list((set(getattr(target, self.name, []))
screamer 29:1210849dba19 271 | self.additions) - self.removals))
screamer 24:25bff2709c20 272
screamer 24:25bff2709c20 273
screamer 29:1210849dba19 274 def _process_config_parameters(data, params, unit_name, unit_kind):
screamer 29:1210849dba19 275 """Process a "config_parameters" section in either a target, a library,
screamer 29:1210849dba19 276 or the application.
screamer 24:25bff2709c20 277
screamer 29:1210849dba19 278 Positional arguments:
screamer 29:1210849dba19 279 data - a dictionary with the configuration parameters
screamer 29:1210849dba19 280 params - storage for the discovered configuration parameters
screamer 29:1210849dba19 281 unit_name - the unit (target/library/application) that defines this
screamer 29:1210849dba19 282 parameter
screamer 29:1210849dba19 283 unit_kind - the kind of the unit ("target", "library" or "application")
screamer 29:1210849dba19 284 """
screamer 29:1210849dba19 285 for name, val in data.items():
screamer 29:1210849dba19 286 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
screamer 29:1210849dba19 287 # If the parameter was already defined, raise an error
screamer 29:1210849dba19 288 if full_name in params:
screamer 29:1210849dba19 289 raise ConfigException(
screamer 29:1210849dba19 290 "Parameter name '%s' defined in both '%s' and '%s'" %
screamer 29:1210849dba19 291 (name, ConfigParameter.get_display_name(unit_name, unit_kind),
screamer 29:1210849dba19 292 params[full_name].defined_by))
screamer 29:1210849dba19 293 # Otherwise add it to the list of known parameters
screamer 29:1210849dba19 294 # If "val" is not a dictionary, this is a shortcut definition,
screamer 29:1210849dba19 295 # otherwise it is a full definition
screamer 29:1210849dba19 296 params[full_name] = ConfigParameter(name, val if isinstance(val, dict)
screamer 29:1210849dba19 297 else {"value": val}, unit_name,
screamer 29:1210849dba19 298 unit_kind)
screamer 29:1210849dba19 299 return params
screamer 29:1210849dba19 300
screamer 29:1210849dba19 301
screamer 29:1210849dba19 302 def _process_macros(mlist, macros, unit_name, unit_kind):
screamer 29:1210849dba19 303 """Process a macro definition and check for incompatible duplicate
screamer 29:1210849dba19 304 definitions.
screamer 29:1210849dba19 305
screamer 29:1210849dba19 306 Positional arguments:
screamer 29:1210849dba19 307 mlist - list of macro names to process
screamer 29:1210849dba19 308 macros - dictionary with currently discovered macros
screamer 29:1210849dba19 309 unit_name - the unit (library/application) that defines this macro
screamer 29:1210849dba19 310 unit_kind - the kind of the unit ("library" or "application")
screamer 29:1210849dba19 311 """
screamer 29:1210849dba19 312 for mname in mlist:
screamer 29:1210849dba19 313 macro = ConfigMacro(mname, unit_name, unit_kind)
screamer 29:1210849dba19 314 if (macro.macro_name in macros) and \
screamer 29:1210849dba19 315 (macros[macro.macro_name].name != mname):
screamer 29:1210849dba19 316 # Found an incompatible definition of the macro in another module,
screamer 29:1210849dba19 317 # so raise an error
screamer 29:1210849dba19 318 full_unit_name = ConfigParameter.get_display_name(unit_name,
screamer 29:1210849dba19 319 unit_kind)
screamer 29:1210849dba19 320 raise ConfigException(
screamer 29:1210849dba19 321 ("Macro '%s' defined in both '%s' and '%s'"
screamer 29:1210849dba19 322 % (macro.macro_name, macros[macro.macro_name].defined_by,
screamer 29:1210849dba19 323 full_unit_name)) +
screamer 29:1210849dba19 324 " with incompatible values")
screamer 29:1210849dba19 325 macros[macro.macro_name] = macro
screamer 29:1210849dba19 326
screamer 29:1210849dba19 327
screamer 29:1210849dba19 328 class Config(object):
screamer 29:1210849dba19 329 """'Config' implements the mbed configuration mechanism"""
screamer 29:1210849dba19 330
screamer 29:1210849dba19 331 # Libraries and applications have different names for their configuration
screamer 29:1210849dba19 332 # files
screamer 8:a8ac6ed29081 333 __mbed_app_config_name = "mbed_app.json"
screamer 8:a8ac6ed29081 334 __mbed_lib_config_name = "mbed_lib.json"
screamer 8:a8ac6ed29081 335
screamer 8:a8ac6ed29081 336 # Allowed keys in configuration dictionaries
screamer 29:1210849dba19 337 # (targets can have any kind of keys, so this validation is not applicable
screamer 29:1210849dba19 338 # to them)
screamer 8:a8ac6ed29081 339 __allowed_keys = {
screamer 29:1210849dba19 340 "library": set(["name", "config", "target_overrides", "macros",
screamer 29:1210849dba19 341 "__config_path"]),
screamer 29:1210849dba19 342 "application": set(["config", "custom_targets", "target_overrides",
screamer 29:1210849dba19 343 "macros", "__config_path"])
screamer 8:a8ac6ed29081 344 }
screamer 8:a8ac6ed29081 345
screamer 13:ab47a20b66f0 346 # Allowed features in configurations
screamer 13:ab47a20b66f0 347 __allowed_features = [
screamer 24:25bff2709c20 348 "UVISOR", "BLE", "CLIENT", "IPV4", "IPV6", "COMMON_PAL", "STORAGE"
screamer 13:ab47a20b66f0 349 ]
screamer 13:ab47a20b66f0 350
screamer 29:1210849dba19 351 def __init__(self, target, top_level_dirs=None):
screamer 29:1210849dba19 352 """Construct a mbed configuration
screamer 29:1210849dba19 353
screamer 29:1210849dba19 354 Positional arguments:
screamer 29:1210849dba19 355 target - the name of the mbed target used for this configuration
screamer 29:1210849dba19 356 instance
screamer 29:1210849dba19 357
screamer 29:1210849dba19 358 Keyword argumets:
screamer 29:1210849dba19 359 top_level_dirs - a list of top level source directories (where
screamer 29:1210849dba19 360 mbed_abb_config.json could be found)
screamer 29:1210849dba19 361
screamer 29:1210849dba19 362 NOTE: Construction of a Config object will look for the application
screamer 29:1210849dba19 363 configuration file in top_level_dirs. If found once, it'll parse it and
screamer 29:1210849dba19 364 check if it has a custom_targets function. If it does, it'll update the
screamer 29:1210849dba19 365 list of targets as needed. If more than one config file is found, an
screamer 29:1210849dba19 366 exception is raised. top_level_dirs may be None (in this case,
screamer 29:1210849dba19 367 the constructor will not search for a configuration file)
screamer 29:1210849dba19 368 """
screamer 8:a8ac6ed29081 369 app_config_location = None
screamer 29:1210849dba19 370 for directory in top_level_dirs or []:
screamer 29:1210849dba19 371 full_path = os.path.join(directory, self.__mbed_app_config_name)
screamer 8:a8ac6ed29081 372 if os.path.isfile(full_path):
screamer 8:a8ac6ed29081 373 if app_config_location is not None:
screamer 29:1210849dba19 374 raise ConfigException("Duplicate '%s' file in '%s' and '%s'"
screamer 29:1210849dba19 375 % (self.__mbed_app_config_name,
screamer 29:1210849dba19 376 app_config_location, full_path))
screamer 8:a8ac6ed29081 377 else:
screamer 8:a8ac6ed29081 378 app_config_location = full_path
screamer 29:1210849dba19 379 self.app_config_data = json_file_to_dict(app_config_location) \
screamer 29:1210849dba19 380 if app_config_location else {}
screamer 8:a8ac6ed29081 381 # Check the keys in the application configuration data
screamer 29:1210849dba19 382 unknown_keys = set(self.app_config_data.keys()) - \
screamer 29:1210849dba19 383 self.__allowed_keys["application"]
screamer 8:a8ac6ed29081 384 if unknown_keys:
screamer 29:1210849dba19 385 raise ConfigException("Unknown key(s) '%s' in %s" %
screamer 29:1210849dba19 386 (",".join(unknown_keys),
screamer 29:1210849dba19 387 self.__mbed_app_config_name))
screamer 29:1210849dba19 388 # Update the list of targets with the ones defined in the application
screamer 29:1210849dba19 389 # config, if applicable
screamer 8:a8ac6ed29081 390 Target.add_py_targets(self.app_config_data.get("custom_targets", {}))
screamer 8:a8ac6ed29081 391 self.lib_config_data = {}
screamer 8:a8ac6ed29081 392 # Make sure that each config is processed only once
screamer 8:a8ac6ed29081 393 self.processed_configs = {}
screamer 13:ab47a20b66f0 394 self.target = target if isinstance(target, basestring) else target.name
screamer 8:a8ac6ed29081 395 self.target_labels = Target.get_target(self.target).get_labels()
screamer 24:25bff2709c20 396
screamer 29:1210849dba19 397 self.cumulative_overrides = {key: ConfigCumulativeOverride(key)
screamer 29:1210849dba19 398 for key in
screamer 29:1210849dba19 399 Target.cumulative_attributes}
screamer 24:25bff2709c20 400
screamer 29:1210849dba19 401 self._process_config_and_overrides(self.app_config_data, {}, "app",
screamer 29:1210849dba19 402 "application")
screamer 24:25bff2709c20 403 self.target_labels = Target.get_target(self.target).get_labels()
screamer 29:1210849dba19 404 self.config_errors = None
screamer 8:a8ac6ed29081 405
screamer 8:a8ac6ed29081 406 def add_config_files(self, flist):
screamer 29:1210849dba19 407 """Add configuration files
screamer 29:1210849dba19 408
screamer 29:1210849dba19 409 Positional arguments:
screamer 29:1210849dba19 410 flist - a list of files to add to this configuration
screamer 29:1210849dba19 411 """
screamer 29:1210849dba19 412 for config_file in flist:
screamer 29:1210849dba19 413 if not config_file.endswith(self.__mbed_lib_config_name):
screamer 8:a8ac6ed29081 414 continue
screamer 29:1210849dba19 415 full_path = os.path.normpath(os.path.abspath(config_file))
screamer 8:a8ac6ed29081 416 # Check that we didn't already process this file
screamer 8:a8ac6ed29081 417 if self.processed_configs.has_key(full_path):
screamer 8:a8ac6ed29081 418 continue
screamer 8:a8ac6ed29081 419 self.processed_configs[full_path] = True
screamer 29:1210849dba19 420 # Read the library configuration and add a "__full_config_path"
screamer 29:1210849dba19 421 # attribute to it
screamer 29:1210849dba19 422 cfg = json_file_to_dict(config_file)
screamer 8:a8ac6ed29081 423 cfg["__config_path"] = full_path
screamer 29:1210849dba19 424
screamer 29:1210849dba19 425 if "name" not in cfg:
screamer 29:1210849dba19 426 raise ConfigException(
screamer 29:1210849dba19 427 "Library configured at %s has no name field." % full_path)
screamer 29:1210849dba19 428 # If there's already a configuration for a module with the same
screamer 29:1210849dba19 429 # name, exit with error
screamer 8:a8ac6ed29081 430 if self.lib_config_data.has_key(cfg["name"]):
screamer 29:1210849dba19 431 raise ConfigException(
screamer 29:1210849dba19 432 "Library name '%s' is not unique (defined in '%s' and '%s')"
screamer 29:1210849dba19 433 % (cfg["name"], full_path,
screamer 29:1210849dba19 434 self.lib_config_data[cfg["name"]]["__config_path"]))
screamer 8:a8ac6ed29081 435 self.lib_config_data[cfg["name"]] = cfg
screamer 8:a8ac6ed29081 436
screamer 29:1210849dba19 437
screamer 29:1210849dba19 438 def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
screamer 29:1210849dba19 439 """Process "config_parameters" and "target_config_overrides" into a
screamer 29:1210849dba19 440 given dictionary
screamer 8:a8ac6ed29081 441
screamer 29:1210849dba19 442 Positional arguments:
screamer 29:1210849dba19 443 data - the configuration data of the library/appliation
screamer 29:1210849dba19 444 params - storage for the discovered configuration parameters
screamer 29:1210849dba19 445 unit_name - the unit (library/application) that defines this parameter
screamer 29:1210849dba19 446 unit_kind - the kind of the unit ("library" or "application")
screamer 29:1210849dba19 447 """
screamer 13:ab47a20b66f0 448 self.config_errors = []
screamer 29:1210849dba19 449 _process_config_parameters(data.get("config", {}), params, unit_name,
screamer 29:1210849dba19 450 unit_kind)
screamer 8:a8ac6ed29081 451 for label, overrides in data.get("target_overrides", {}).items():
screamer 29:1210849dba19 452 # If the label is defined by the target or it has the special value
screamer 29:1210849dba19 453 # "*", process the overrides
screamer 8:a8ac6ed29081 454 if (label == '*') or (label in self.target_labels):
screamer 24:25bff2709c20 455 # Check for invalid cumulative overrides in libraries
screamer 29:1210849dba19 456 if (unit_kind == 'library' and
screamer 29:1210849dba19 457 any(attr.startswith('target.extra_labels') for attr
screamer 29:1210849dba19 458 in overrides.iterkeys())):
screamer 29:1210849dba19 459 raise ConfigException(
screamer 29:1210849dba19 460 "Target override 'target.extra_labels' in " +
screamer 29:1210849dba19 461 ConfigParameter.get_display_name(unit_name, unit_kind,
screamer 29:1210849dba19 462 label) +
screamer 29:1210849dba19 463 " is only allowed at the application level")
Screamer@Y5070-M.virtuoso 10:2511036308b8 464
screamer 24:25bff2709c20 465 # Parse out cumulative overrides
screamer 24:25bff2709c20 466 for attr, cumulatives in self.cumulative_overrides.iteritems():
screamer 24:25bff2709c20 467 if 'target.'+attr in overrides:
screamer 29:1210849dba19 468 cumulatives.strict_cumulative_overrides(
screamer 29:1210849dba19 469 overrides['target.'+attr])
screamer 24:25bff2709c20 470 del overrides['target.'+attr]
Screamer@Y5070-M.virtuoso 10:2511036308b8 471
screamer 24:25bff2709c20 472 if 'target.'+attr+'_add' in overrides:
screamer 29:1210849dba19 473 cumulatives.add_cumulative_overrides(
screamer 29:1210849dba19 474 overrides['target.'+attr+'_add'])
screamer 24:25bff2709c20 475 del overrides['target.'+attr+'_add']
screamer 24:25bff2709c20 476
screamer 24:25bff2709c20 477 if 'target.'+attr+'_remove' in overrides:
screamer 29:1210849dba19 478 cumulatives.remove_cumulative_overrides(
screamer 29:1210849dba19 479 overrides['target.'+attr+'_remove'])
screamer 24:25bff2709c20 480 del overrides['target.'+attr+'_remove']
Screamer@Y5070-M.virtuoso 10:2511036308b8 481
Screamer@Y5070-M.virtuoso 10:2511036308b8 482 # Consider the others as overrides
screamer 29:1210849dba19 483 for name, val in overrides.items():
screamer 8:a8ac6ed29081 484 # Get the full name of the parameter
screamer 29:1210849dba19 485 full_name = ConfigParameter.get_full_name(name, unit_name,
screamer 29:1210849dba19 486 unit_kind, label)
screamer 13:ab47a20b66f0 487 if full_name in params:
screamer 29:1210849dba19 488 params[full_name].set_value(val, unit_name, unit_kind,
screamer 29:1210849dba19 489 label)
screamer 13:ab47a20b66f0 490 else:
screamer 29:1210849dba19 491 self.config_errors.append(
screamer 29:1210849dba19 492 ConfigException(
screamer 29:1210849dba19 493 "Attempt to override undefined parameter" +
screamer 29:1210849dba19 494 (" '%s' in '%s'"
screamer 29:1210849dba19 495 % (full_name,
screamer 29:1210849dba19 496 ConfigParameter.get_display_name(unit_name,
screamer 29:1210849dba19 497 unit_kind,
screamer 29:1210849dba19 498 label)))))
screamer 24:25bff2709c20 499
screamer 24:25bff2709c20 500 for cumulatives in self.cumulative_overrides.itervalues():
screamer 24:25bff2709c20 501 cumulatives.update_target(Target.get_target(self.target))
screamer 24:25bff2709c20 502
screamer 8:a8ac6ed29081 503 return params
screamer 8:a8ac6ed29081 504
screamer 8:a8ac6ed29081 505 def get_target_config_data(self):
screamer 29:1210849dba19 506 """Read and interpret configuration data defined by targets.
screamer 29:1210849dba19 507
screamer 29:1210849dba19 508 We consider the resolution order for our target and sort it by level
screamer 29:1210849dba19 509 reversed, so that we first look at the top level target (the parent),
screamer 29:1210849dba19 510 then its direct children, then the children of those children and so on,
screamer 29:1210849dba19 511 until we reach self.target
screamer 29:1210849dba19 512 TODO: this might not work so well in some multiple inheritance scenarios
screamer 29:1210849dba19 513 At each step, look at two keys of the target data:
screamer 29:1210849dba19 514 - config_parameters: used to define new configuration parameters
screamer 29:1210849dba19 515 - config_overrides: used to override already defined configuration
screamer 29:1210849dba19 516 parameters
screamer 29:1210849dba19 517
screamer 29:1210849dba19 518 Arguments: None
screamer 29:1210849dba19 519 """
screamer 8:a8ac6ed29081 520 params, json_data = {}, Target.get_json_target_data()
screamer 29:1210849dba19 521 resolution_order = [e[0] for e
screamer 29:1210849dba19 522 in sorted(
screamer 29:1210849dba19 523 Target.get_target(self.target).resolution_order,
screamer 29:1210849dba19 524 key=lambda e: e[1], reverse=True)]
screamer 8:a8ac6ed29081 525 for tname in resolution_order:
screamer 8:a8ac6ed29081 526 # Read the target data directly from its description
screamer 29:1210849dba19 527 target_data = json_data[tname]
screamer 8:a8ac6ed29081 528 # Process definitions first
screamer 29:1210849dba19 529 _process_config_parameters(target_data.get("config", {}), params,
screamer 29:1210849dba19 530 tname, "target")
screamer 8:a8ac6ed29081 531 # Then process overrides
screamer 29:1210849dba19 532 for name, val in target_data.get("overrides", {}).items():
screamer 8:a8ac6ed29081 533 full_name = ConfigParameter.get_full_name(name, tname, "target")
screamer 29:1210849dba19 534 # If the parameter name is not defined or if there isn't a path
screamer 29:1210849dba19 535 # from this target to the target where the parameter was defined
screamer 29:1210849dba19 536 # in the target inheritance tree, raise an error We need to use
screamer 29:1210849dba19 537 # 'defined_by[7:]' to remove the "target:" prefix from
screamer 29:1210849dba19 538 # defined_by
screamer 29:1210849dba19 539 if (full_name not in params) or \
screamer 29:1210849dba19 540 (params[full_name].defined_by[7:] not in
screamer 29:1210849dba19 541 Target.get_target(tname).resolution_order_names):
screamer 29:1210849dba19 542 raise ConfigException(
screamer 29:1210849dba19 543 "Attempt to override undefined parameter '%s' in '%s'"
screamer 29:1210849dba19 544 % (name,
screamer 29:1210849dba19 545 ConfigParameter.get_display_name(tname, "target")))
screamer 8:a8ac6ed29081 546 # Otherwise update the value of the parameter
screamer 29:1210849dba19 547 params[full_name].set_value(val, tname, "target")
screamer 8:a8ac6ed29081 548 return params
screamer 8:a8ac6ed29081 549
screamer 29:1210849dba19 550 def get_lib_config_data(self):
screamer 29:1210849dba19 551 """ Read and interpret configuration data defined by libraries. It is
screamer 29:1210849dba19 552 assumed that "add_config_files" above was already called and the library
screamer 29:1210849dba19 553 configuration data exists in self.lib_config_data
screamer 8:a8ac6ed29081 554
screamer 29:1210849dba19 555 Arguments: None
screamer 29:1210849dba19 556 """
screamer 8:a8ac6ed29081 557 all_params, macros = {}, {}
screamer 8:a8ac6ed29081 558 for lib_name, lib_data in self.lib_config_data.items():
screamer 8:a8ac6ed29081 559 unknown_keys = set(lib_data.keys()) - self.__allowed_keys["library"]
screamer 8:a8ac6ed29081 560 if unknown_keys:
screamer 29:1210849dba19 561 raise ConfigException("Unknown key(s) '%s' in %s" %
screamer 29:1210849dba19 562 (",".join(unknown_keys), lib_name))
screamer 29:1210849dba19 563 all_params.update(self._process_config_and_overrides(lib_data, {},
screamer 29:1210849dba19 564 lib_name,
screamer 29:1210849dba19 565 "library"))
screamer 29:1210849dba19 566 _process_macros(lib_data.get("macros", []), macros, lib_name,
screamer 29:1210849dba19 567 "library")
screamer 8:a8ac6ed29081 568 return all_params, macros
screamer 8:a8ac6ed29081 569
screamer 8:a8ac6ed29081 570 def get_app_config_data(self, params, macros):
screamer 29:1210849dba19 571 """ Read and interpret the configuration data defined by the target. The
screamer 29:1210849dba19 572 target can override any configuration parameter, as well as define its
screamer 29:1210849dba19 573 own configuration data.
screamer 29:1210849dba19 574
screamer 29:1210849dba19 575 Positional arguments.
screamer 29:1210849dba19 576 params - the dictionary with configuration parameters found so far (in
screamer 29:1210849dba19 577 the target and in libraries)
screamer 29:1210849dba19 578 macros - the list of macros defined in the configuration
screamer 29:1210849dba19 579 """
screamer 8:a8ac6ed29081 580 app_cfg = self.app_config_data
screamer 29:1210849dba19 581 # The application can have a "config_parameters" and a
screamer 29:1210849dba19 582 # "target_config_overrides" section just like a library
screamer 29:1210849dba19 583 self._process_config_and_overrides(app_cfg, params, "app",
screamer 29:1210849dba19 584 "application")
screamer 8:a8ac6ed29081 585 # The application can also defined macros
screamer 29:1210849dba19 586 _process_macros(app_cfg.get("macros", []), macros, "app",
screamer 29:1210849dba19 587 "application")
screamer 8:a8ac6ed29081 588
screamer 8:a8ac6ed29081 589 def get_config_data(self):
screamer 29:1210849dba19 590 """ Return the configuration data in two parts: (params, macros)
screamer 29:1210849dba19 591 params - a dictionary with mapping a name to a ConfigParam
screamer 29:1210849dba19 592 macros - the list of macros defined with "macros" in libraries and in
screamer 29:1210849dba19 593 the application (as ConfigMacro instances)
screamer 29:1210849dba19 594
screamer 29:1210849dba19 595 Arguments: None
screamer 29:1210849dba19 596 """
screamer 8:a8ac6ed29081 597 all_params = self.get_target_config_data()
screamer 8:a8ac6ed29081 598 lib_params, macros = self.get_lib_config_data()
screamer 8:a8ac6ed29081 599 all_params.update(lib_params)
screamer 8:a8ac6ed29081 600 self.get_app_config_data(all_params, macros)
screamer 13:ab47a20b66f0 601 return all_params, macros
screamer 8:a8ac6ed29081 602
screamer 13:ab47a20b66f0 603 @staticmethod
screamer 13:ab47a20b66f0 604 def _check_required_parameters(params):
screamer 29:1210849dba19 605 """Check that there are no required parameters without a value
screamer 29:1210849dba19 606
screamer 29:1210849dba19 607 Positional arguments:
screamer 29:1210849dba19 608 params - the list of parameters to check
screamer 8:a8ac6ed29081 609
screamer 29:1210849dba19 610 NOTE: This function does not return. Instead, it throws a
screamer 29:1210849dba19 611 ConfigException when any of the required parameters are missing values
screamer 29:1210849dba19 612 """
screamer 29:1210849dba19 613 for param in params.values():
screamer 29:1210849dba19 614 if param.required and (param.value is None):
screamer 29:1210849dba19 615 raise ConfigException("Required parameter '" + param.name +
screamer 29:1210849dba19 616 "' defined by '" + param.defined_by +
screamer 29:1210849dba19 617 "' doesn't have a value")
screamer 29:1210849dba19 618
screamer 8:a8ac6ed29081 619 @staticmethod
screamer 8:a8ac6ed29081 620 def parameters_to_macros(params):
screamer 29:1210849dba19 621 """ Encode the configuration parameters as C macro definitions.
screamer 29:1210849dba19 622
screamer 29:1210849dba19 623 Positional arguments:
screamer 29:1210849dba19 624 params - a dictionary mapping a name to a ConfigParameter
screamer 8:a8ac6ed29081 625
screamer 29:1210849dba19 626 Return: a list of strings that encode the configuration parameters as
screamer 29:1210849dba19 627 C pre-processor macros
screamer 29:1210849dba19 628 """
screamer 29:1210849dba19 629 return ['%s=%s' % (m.macro_name, m.value) for m in params.values()
screamer 29:1210849dba19 630 if m.value is not None]
screamer 29:1210849dba19 631
screamer 13:ab47a20b66f0 632 @staticmethod
screamer 13:ab47a20b66f0 633 def config_macros_to_macros(macros):
screamer 29:1210849dba19 634 """ Return the macro definitions generated for a dictionary of
screamer 29:1210849dba19 635 ConfigMacros (as returned by get_config_data).
screamer 29:1210849dba19 636
screamer 29:1210849dba19 637 Positional arguments:
screamer 29:1210849dba19 638 params - a dictionary mapping a name to a ConfigMacro instance
screamer 29:1210849dba19 639
screamer 29:1210849dba19 640 Return: a list of strings that are the C pre-processor macros
screamer 29:1210849dba19 641 """
screamer 13:ab47a20b66f0 642 return [m.name for m in macros.values()]
screamer 13:ab47a20b66f0 643
screamer 13:ab47a20b66f0 644 @staticmethod
screamer 13:ab47a20b66f0 645 def config_to_macros(config):
screamer 29:1210849dba19 646 """Convert the configuration data to a list of C macros
screamer 29:1210849dba19 647
screamer 29:1210849dba19 648 Positional arguments:
screamer 29:1210849dba19 649 config - configuration data as (ConfigParam instances, ConfigMacro
screamer 29:1210849dba19 650 instances) tuple (as returned by get_config_data())
screamer 29:1210849dba19 651 """
screamer 13:ab47a20b66f0 652 params, macros = config[0], config[1]
screamer 13:ab47a20b66f0 653 Config._check_required_parameters(params)
screamer 29:1210849dba19 654 return Config.config_macros_to_macros(macros) + \
screamer 29:1210849dba19 655 Config.parameters_to_macros(params)
screamer 13:ab47a20b66f0 656
screamer 8:a8ac6ed29081 657 def get_config_data_macros(self):
screamer 29:1210849dba19 658 """ Convert a Config object to a list of C macros
screamer 29:1210849dba19 659
screamer 29:1210849dba19 660 Arguments: None
screamer 29:1210849dba19 661 """
screamer 13:ab47a20b66f0 662 return self.config_to_macros(self.get_config_data())
screamer 13:ab47a20b66f0 663
screamer 13:ab47a20b66f0 664 def get_features(self):
screamer 29:1210849dba19 665 """ Extract any features from the configuration data
screamer 29:1210849dba19 666
screamer 29:1210849dba19 667 Arguments: None
screamer 29:1210849dba19 668 """
screamer 13:ab47a20b66f0 669 params, _ = self.get_config_data()
screamer 8:a8ac6ed29081 670 self._check_required_parameters(params)
screamer 29:1210849dba19 671 self.cumulative_overrides['features']\
screamer 29:1210849dba19 672 .update_target(Target.get_target(self.target))
screamer 24:25bff2709c20 673 features = Target.get_target(self.target).features
screamer 13:ab47a20b66f0 674
screamer 13:ab47a20b66f0 675 for feature in features:
screamer 13:ab47a20b66f0 676 if feature not in self.__allowed_features:
screamer 29:1210849dba19 677 raise ConfigException(
screamer 29:1210849dba19 678 "Feature '%s' is not a supported features" % feature)
screamer 13:ab47a20b66f0 679
screamer 13:ab47a20b66f0 680 return features
screamer 13:ab47a20b66f0 681
screamer 13:ab47a20b66f0 682 def validate_config(self):
screamer 29:1210849dba19 683 """ Validate configuration settings. This either returns True or
screamer 29:1210849dba19 684 raises an exception
screamer 29:1210849dba19 685
screamer 29:1210849dba19 686 Arguments: None
screamer 29:1210849dba19 687 """
screamer 13:ab47a20b66f0 688 if self.config_errors:
screamer 13:ab47a20b66f0 689 raise self.config_errors[0]
screamer 13:ab47a20b66f0 690 return True
screamer 13:ab47a20b66f0 691
screamer 13:ab47a20b66f0 692
screamer 13:ab47a20b66f0 693 def load_resources(self, resources):
screamer 29:1210849dba19 694 """ Load configuration data from a Resources instance and expand it
screamer 29:1210849dba19 695 based on defined features.
screamer 29:1210849dba19 696
screamer 29:1210849dba19 697 Positional arguments:
screamer 29:1210849dba19 698 resources - the resources object to load from and expand
screamer 29:1210849dba19 699 """
screamer 13:ab47a20b66f0 700 # Update configuration files until added features creates no changes
screamer 13:ab47a20b66f0 701 prev_features = set()
screamer 13:ab47a20b66f0 702 while True:
screamer 29:1210849dba19 703 # Add/update the configuration with any .json files found while
screamer 29:1210849dba19 704 # scanning
screamer 13:ab47a20b66f0 705 self.add_config_files(resources.json_files)
screamer 13:ab47a20b66f0 706
screamer 13:ab47a20b66f0 707 # Add features while we find new ones
screamer 29:1210849dba19 708 features = set(self.get_features())
screamer 13:ab47a20b66f0 709 if features == prev_features:
screamer 13:ab47a20b66f0 710 break
screamer 13:ab47a20b66f0 711
screamer 13:ab47a20b66f0 712 for feature in features:
screamer 13:ab47a20b66f0 713 if feature in resources.features:
screamer 13:ab47a20b66f0 714 resources.add(resources.features[feature])
screamer 13:ab47a20b66f0 715
screamer 13:ab47a20b66f0 716 prev_features = features
screamer 13:ab47a20b66f0 717 self.validate_config()
screamer 13:ab47a20b66f0 718
screamer 13:ab47a20b66f0 719 return resources
screamer 13:ab47a20b66f0 720
screamer 13:ab47a20b66f0 721 @staticmethod
screamer 29:1210849dba19 722 def config_to_header(config, fname=None):
screamer 29:1210849dba19 723 """ Convert the configuration data to the content of a C header file,
screamer 29:1210849dba19 724 meant to be included to a C/C++ file. The content is returned as a
screamer 29:1210849dba19 725 string.
screamer 29:1210849dba19 726
screamer 29:1210849dba19 727 Positional arguments:
screamer 29:1210849dba19 728 config - configuration data as (ConfigParam instances, ConfigMacro
screamer 29:1210849dba19 729 instances) tuple (as returned by get_config_data())
screamer 29:1210849dba19 730
screamer 29:1210849dba19 731 Keyword arguments:
screamer 29:1210849dba19 732 fname - also write the content is to the file called "fname".
screamer 29:1210849dba19 733 WARNING: if 'fname' names an existing file, it will be
screamer 29:1210849dba19 734 overwritten!
screamer 29:1210849dba19 735 """
screamer 13:ab47a20b66f0 736 params, macros = config[0], config[1]
screamer 13:ab47a20b66f0 737 Config._check_required_parameters(params)
screamer 29:1210849dba19 738 header_data = "// Automatically generated configuration file.\n"
screamer 13:ab47a20b66f0 739 header_data += "// DO NOT EDIT, content will be overwritten.\n\n"
screamer 13:ab47a20b66f0 740 header_data += "#ifndef __MBED_CONFIG_DATA__\n"
screamer 13:ab47a20b66f0 741 header_data += "#define __MBED_CONFIG_DATA__\n\n"
screamer 13:ab47a20b66f0 742 # Compute maximum length of macro names for proper alignment
screamer 29:1210849dba19 743 max_param_macro_name_len = (max([len(m.macro_name) for m
screamer 29:1210849dba19 744 in params.values()
screamer 29:1210849dba19 745 if m.value is not None])
screamer 29:1210849dba19 746 if params else 0)
screamer 29:1210849dba19 747 max_direct_macro_name_len = (max([len(m.macro_name) for m
screamer 29:1210849dba19 748 in macros.values()])
screamer 29:1210849dba19 749 if macros else 0)
screamer 29:1210849dba19 750 max_macro_name_len = max(max_param_macro_name_len,
screamer 29:1210849dba19 751 max_direct_macro_name_len)
screamer 13:ab47a20b66f0 752 # Compute maximum length of macro values for proper alignment
screamer 29:1210849dba19 753 max_param_macro_val_len = (max([len(str(m.value)) for m
screamer 29:1210849dba19 754 in params.values()
screamer 29:1210849dba19 755 if m.value is not None])
screamer 29:1210849dba19 756 if params else 0)
screamer 29:1210849dba19 757 max_direct_macro_val_len = max([len(m.macro_value or "") for m
screamer 29:1210849dba19 758 in macros.values()]) if macros else 0
screamer 29:1210849dba19 759 max_macro_val_len = max(max_param_macro_val_len,
screamer 29:1210849dba19 760 max_direct_macro_val_len)
screamer 13:ab47a20b66f0 761 # Generate config parameters first
screamer 13:ab47a20b66f0 762 if params:
screamer 13:ab47a20b66f0 763 header_data += "// Configuration parameters\n"
screamer 29:1210849dba19 764 for macro in params.values():
screamer 29:1210849dba19 765 if macro.value is not None:
screamer 29:1210849dba19 766 header_data += ("#define {0:<{1}} {2!s:<{3}} " +
screamer 29:1210849dba19 767 "// set by {4}\n")\
screamer 29:1210849dba19 768 .format(macro.macro_name, max_macro_name_len,
screamer 29:1210849dba19 769 macro.value, max_macro_val_len, macro.set_by)
screamer 13:ab47a20b66f0 770 # Then macros
screamer 13:ab47a20b66f0 771 if macros:
screamer 13:ab47a20b66f0 772 header_data += "// Macros\n"
screamer 29:1210849dba19 773 for macro in macros.values():
screamer 29:1210849dba19 774 if macro.macro_value:
screamer 29:1210849dba19 775 header_data += ("#define {0:<{1}} {2!s:<{3}}" +
screamer 29:1210849dba19 776 " // defined by {4}\n")\
screamer 30:f12ce67666d0 777 .format(m.macro_name, max_macro_name_len, m.macro_value,
screamer 30:f12ce67666d0 778 max_macro_val_len, m.defined_by)
screamer 13:ab47a20b66f0 779 else:
screamer 29:1210849dba19 780 header_data += ("#define {0:<{1}}" +
screamer 29:1210849dba19 781 " // defined by {2}\n")\
screamer 30:f12ce67666d0 782 .format(m.macro_name,
screamer 29:1210849dba19 783 max_macro_name_len + max_macro_val_len + 1,
screamer 30:f12ce67666d0 784 m.defined_by)
screamer 13:ab47a20b66f0 785 header_data += "\n#endif\n"
screamer 13:ab47a20b66f0 786 # If fname is given, write "header_data" to it
screamer 13:ab47a20b66f0 787 if fname:
screamer 29:1210849dba19 788 with open(fname, "w+") as file_desc:
screamer 29:1210849dba19 789 file_desc.write(header_data)
screamer 13:ab47a20b66f0 790 return header_data
screamer 13:ab47a20b66f0 791
screamer 29:1210849dba19 792 def get_config_data_header(self, fname=None):
screamer 29:1210849dba19 793 """ Convert a Config instance to the content of a C header file, meant
screamer 29:1210849dba19 794 to be included to a C/C++ file. The content is returned as a string.
screamer 29:1210849dba19 795
screamer 29:1210849dba19 796 Keyword arguments:
screamer 29:1210849dba19 797 fname - also write the content to the file called "fname".
screamer 29:1210849dba19 798 WARNING: if 'fname' names an existing file, it will be
screamer 29:1210849dba19 799 overwritten!
screamer 29:1210849dba19 800 """
screamer 13:ab47a20b66f0 801 return self.config_to_header(self.get_config_data(), fname)