nkjnm

Dependencies:   MAX44000 nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

Committer:
nitsshukla
Date:
Fri Nov 04 12:06:04 2016 +0000
Revision:
7:3a65ef12ba31
Parent:
1:55a6170b404f
kghj;

Who changed what in which revision?

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