Includes library modifications to allow access to AIN_4 (AIN_0 / 5)

Committer:
bryantaylor
Date:
Tue Sep 20 21:26:12 2016 +0000
Revision:
0:eafc3fd41f75
hackathon

Who changed what in which revision?

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