Backup 1

Committer:
borlanic
Date:
Tue Apr 24 11:45:18 2018 +0000
Revision:
0:02dd72d1d465
BaBoRo_test2 - backup 1

Who changed what in which revision?

UserRevisionLine numberNew contents of line
borlanic 0:02dd72d1d465 1 """
borlanic 0:02dd72d1d465 2 mbed SDK
borlanic 0:02dd72d1d465 3 Copyright (c) 2016 ARM Limited
borlanic 0:02dd72d1d465 4
borlanic 0:02dd72d1d465 5 Licensed under the Apache License, Version 2.0 (the "License");
borlanic 0:02dd72d1d465 6 you may not use this file except in compliance with the License.
borlanic 0:02dd72d1d465 7 You may obtain a copy of the License at
borlanic 0:02dd72d1d465 8
borlanic 0:02dd72d1d465 9 http://www.apache.org/licenses/LICENSE-2.0
borlanic 0:02dd72d1d465 10
borlanic 0:02dd72d1d465 11 Unless required by applicable law or agreed to in writing, software
borlanic 0:02dd72d1d465 12 distributed under the License is distributed on an "AS IS" BASIS,
borlanic 0:02dd72d1d465 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
borlanic 0:02dd72d1d465 14 See the License for the specific language governing permissions and
borlanic 0:02dd72d1d465 15 limitations under the License.
borlanic 0:02dd72d1d465 16 """
borlanic 0:02dd72d1d465 17 from __future__ import print_function, division, absolute_import
borlanic 0:02dd72d1d465 18
borlanic 0:02dd72d1d465 19 from copy import deepcopy
borlanic 0:02dd72d1d465 20 from six import moves
borlanic 0:02dd72d1d465 21 import json
borlanic 0:02dd72d1d465 22 import six
borlanic 0:02dd72d1d465 23 import os
borlanic 0:02dd72d1d465 24 from os.path import dirname, abspath, exists, join, isabs
borlanic 0:02dd72d1d465 25 import sys
borlanic 0:02dd72d1d465 26 from collections import namedtuple
borlanic 0:02dd72d1d465 27 from os.path import splitext, relpath
borlanic 0:02dd72d1d465 28 from intelhex import IntelHex
borlanic 0:02dd72d1d465 29 from jinja2 import FileSystemLoader, StrictUndefined
borlanic 0:02dd72d1d465 30 from jinja2.environment import Environment
borlanic 0:02dd72d1d465 31 from jsonschema import Draft4Validator, RefResolver
borlanic 0:02dd72d1d465 32
borlanic 0:02dd72d1d465 33 from ..utils import (json_file_to_dict, intelhex_offset, integer,
borlanic 0:02dd72d1d465 34 NotSupportedException)
borlanic 0:02dd72d1d465 35 from ..arm_pack_manager import Cache
borlanic 0:02dd72d1d465 36 from ..targets import (CUMULATIVE_ATTRIBUTES, TARGET_MAP, generate_py_target,
borlanic 0:02dd72d1d465 37 get_resolution_order, Target)
borlanic 0:02dd72d1d465 38
borlanic 0:02dd72d1d465 39 try:
borlanic 0:02dd72d1d465 40 unicode
borlanic 0:02dd72d1d465 41 except NameError:
borlanic 0:02dd72d1d465 42 unicode = str
borlanic 0:02dd72d1d465 43 PATH_OVERRIDES = set(["target.bootloader_img"])
borlanic 0:02dd72d1d465 44 BOOTLOADER_OVERRIDES = set(["target.bootloader_img", "target.restrict_size",
borlanic 0:02dd72d1d465 45 "target.header_format", "target.header_offset",
borlanic 0:02dd72d1d465 46 "target.app_offset",
borlanic 0:02dd72d1d465 47 "target.mbed_app_start", "target.mbed_app_size"])
borlanic 0:02dd72d1d465 48
borlanic 0:02dd72d1d465 49
borlanic 0:02dd72d1d465 50 # Base class for all configuration exceptions
borlanic 0:02dd72d1d465 51 class ConfigException(Exception):
borlanic 0:02dd72d1d465 52 """Config system only exception. Makes it easier to distinguish config
borlanic 0:02dd72d1d465 53 errors"""
borlanic 0:02dd72d1d465 54 pass
borlanic 0:02dd72d1d465 55
borlanic 0:02dd72d1d465 56 class ConfigParameter(object):
borlanic 0:02dd72d1d465 57 """This class keeps information about a single configuration parameter"""
borlanic 0:02dd72d1d465 58
borlanic 0:02dd72d1d465 59 def __init__(self, name, data, unit_name, unit_kind):
borlanic 0:02dd72d1d465 60 """Construct a ConfigParameter
borlanic 0:02dd72d1d465 61
borlanic 0:02dd72d1d465 62 Positional arguments:
borlanic 0:02dd72d1d465 63 name - the name of the configuration parameter
borlanic 0:02dd72d1d465 64 data - the data associated with the configuration parameter
borlanic 0:02dd72d1d465 65 unit_name - the unit (target/library/application) that defines this
borlanic 0:02dd72d1d465 66 parameter
borlanic 0:02dd72d1d465 67 unit_ kind - the kind of the unit ("target", "library" or "application")
borlanic 0:02dd72d1d465 68 """
borlanic 0:02dd72d1d465 69 self.name = self.get_full_name(name, unit_name, unit_kind,
borlanic 0:02dd72d1d465 70 allow_prefix=False)
borlanic 0:02dd72d1d465 71 self.defined_by = self.get_display_name(unit_name, unit_kind)
borlanic 0:02dd72d1d465 72 self.set_value(data.get("value", None), unit_name, unit_kind)
borlanic 0:02dd72d1d465 73 self.help_text = data.get("help", None)
borlanic 0:02dd72d1d465 74 self.required = data.get("required", False)
borlanic 0:02dd72d1d465 75 self.macro_name = data.get("macro_name", "MBED_CONF_%s" %
borlanic 0:02dd72d1d465 76 self.sanitize(self.name.upper()))
borlanic 0:02dd72d1d465 77 self.config_errors = []
borlanic 0:02dd72d1d465 78
borlanic 0:02dd72d1d465 79 @staticmethod
borlanic 0:02dd72d1d465 80 def get_full_name(name, unit_name, unit_kind, label=None,
borlanic 0:02dd72d1d465 81 allow_prefix=True):
borlanic 0:02dd72d1d465 82 """Return the full (prefixed) name of a parameter. If the parameter
borlanic 0:02dd72d1d465 83 already has a prefix, check if it is valid
borlanic 0:02dd72d1d465 84
borlanic 0:02dd72d1d465 85 Positional arguments:
borlanic 0:02dd72d1d465 86 name - the simple (unqualified) name of the parameter
borlanic 0:02dd72d1d465 87 unit_name - the unit (target/library/application) that defines this
borlanic 0:02dd72d1d465 88 parameter
borlanic 0:02dd72d1d465 89 unit_kind - the kind of the unit ("target", "library" or "application")
borlanic 0:02dd72d1d465 90
borlanic 0:02dd72d1d465 91 Keyword arguments:
borlanic 0:02dd72d1d465 92 label - the name of the label in the 'target_config_overrides' section
borlanic 0:02dd72d1d465 93 allow_prefix - True to allow the original name to have a prefix, False
borlanic 0:02dd72d1d465 94 otherwise
borlanic 0:02dd72d1d465 95 """
borlanic 0:02dd72d1d465 96 if name.find('.') == -1: # the name is not prefixed
borlanic 0:02dd72d1d465 97 if unit_kind == "target":
borlanic 0:02dd72d1d465 98 prefix = "target."
borlanic 0:02dd72d1d465 99 elif unit_kind == "application":
borlanic 0:02dd72d1d465 100 prefix = "app."
borlanic 0:02dd72d1d465 101 else:
borlanic 0:02dd72d1d465 102 prefix = unit_name + '.'
borlanic 0:02dd72d1d465 103 return prefix + name
borlanic 0:02dd72d1d465 104 if name in BOOTLOADER_OVERRIDES:
borlanic 0:02dd72d1d465 105 return name
borlanic 0:02dd72d1d465 106 # The name has a prefix, so check if it is valid
borlanic 0:02dd72d1d465 107 if not allow_prefix:
borlanic 0:02dd72d1d465 108 raise ConfigException("Invalid parameter name '%s' in '%s'" %
borlanic 0:02dd72d1d465 109 (name, ConfigParameter.get_display_name(
borlanic 0:02dd72d1d465 110 unit_name, unit_kind, label)))
borlanic 0:02dd72d1d465 111 temp = name.split(".")
borlanic 0:02dd72d1d465 112 # Check if the parameter syntax is correct (must be
borlanic 0:02dd72d1d465 113 # unit_name.parameter_name)
borlanic 0:02dd72d1d465 114 if len(temp) != 2:
borlanic 0:02dd72d1d465 115 raise ConfigException("Invalid parameter name '%s' in '%s'" %
borlanic 0:02dd72d1d465 116 (name, ConfigParameter.get_display_name(
borlanic 0:02dd72d1d465 117 unit_name, unit_kind, label)))
borlanic 0:02dd72d1d465 118 prefix = temp[0]
borlanic 0:02dd72d1d465 119 # Check if the given parameter prefix matches the expected prefix
borlanic 0:02dd72d1d465 120 if (unit_kind == "library" and prefix != unit_name) or \
borlanic 0:02dd72d1d465 121 (unit_kind == "target" and prefix != "target"):
borlanic 0:02dd72d1d465 122 raise ConfigException(
borlanic 0:02dd72d1d465 123 "Invalid prefix '%s' for parameter name '%s' in '%s'" %
borlanic 0:02dd72d1d465 124 (prefix, name, ConfigParameter.get_display_name(
borlanic 0:02dd72d1d465 125 unit_name, unit_kind, label)))
borlanic 0:02dd72d1d465 126 return name
borlanic 0:02dd72d1d465 127
borlanic 0:02dd72d1d465 128 @staticmethod
borlanic 0:02dd72d1d465 129 def get_display_name(unit_name, unit_kind, label=None):
borlanic 0:02dd72d1d465 130 """Return the name displayed for a unit when interrogating the origin
borlanic 0:02dd72d1d465 131 and the last set place of a parameter
borlanic 0:02dd72d1d465 132
borlanic 0:02dd72d1d465 133 Positional arguments:
borlanic 0:02dd72d1d465 134 unit_name - the unit (target/library/application) that defines this
borlanic 0:02dd72d1d465 135 parameter
borlanic 0:02dd72d1d465 136 unit_kind - the kind of the unit ("target", "library" or "application")
borlanic 0:02dd72d1d465 137
borlanic 0:02dd72d1d465 138 Keyword arguments:
borlanic 0:02dd72d1d465 139 label - the name of the label in the 'target_config_overrides' section
borlanic 0:02dd72d1d465 140 """
borlanic 0:02dd72d1d465 141 if unit_kind == "target":
borlanic 0:02dd72d1d465 142 return "target:" + unit_name
borlanic 0:02dd72d1d465 143 elif unit_kind == "application":
borlanic 0:02dd72d1d465 144 return "application%s" % ("[%s]" % label if label else "")
borlanic 0:02dd72d1d465 145 else: # library
borlanic 0:02dd72d1d465 146 return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
borlanic 0:02dd72d1d465 147
borlanic 0:02dd72d1d465 148 @staticmethod
borlanic 0:02dd72d1d465 149 def sanitize(name):
borlanic 0:02dd72d1d465 150 """ "Sanitize" a name so that it is a valid C macro name. Currently it
borlanic 0:02dd72d1d465 151 simply replaces '.' and '-' with '_'.
borlanic 0:02dd72d1d465 152
borlanic 0:02dd72d1d465 153 Positional arguments:
borlanic 0:02dd72d1d465 154 name - the name to make into a valid C macro
borlanic 0:02dd72d1d465 155 """
borlanic 0:02dd72d1d465 156 return name.replace('.', '_').replace('-', '_')
borlanic 0:02dd72d1d465 157
borlanic 0:02dd72d1d465 158 def set_value(self, value, unit_name, unit_kind, label=None):
borlanic 0:02dd72d1d465 159 """ Sets a value for this parameter, remember the place where it was
borlanic 0:02dd72d1d465 160 set. If the value is a Boolean, it is converted to 1 (for True) or
borlanic 0:02dd72d1d465 161 to 0 (for False).
borlanic 0:02dd72d1d465 162
borlanic 0:02dd72d1d465 163 Positional arguments:
borlanic 0:02dd72d1d465 164 value - the value of the parameter
borlanic 0:02dd72d1d465 165 unit_name - the unit (target/library/application) that defines this
borlanic 0:02dd72d1d465 166 parameter
borlanic 0:02dd72d1d465 167 unit_kind - the kind of the unit ("target", "library" or "application")
borlanic 0:02dd72d1d465 168
borlanic 0:02dd72d1d465 169 Keyword arguments:
borlanic 0:02dd72d1d465 170 label - the name of the label in the 'target_config_overrides' section
borlanic 0:02dd72d1d465 171 (optional)
borlanic 0:02dd72d1d465 172 """
borlanic 0:02dd72d1d465 173 self.value = int(value) if isinstance(value, bool) else value
borlanic 0:02dd72d1d465 174 self.set_by = self.get_display_name(unit_name, unit_kind, label)
borlanic 0:02dd72d1d465 175
borlanic 0:02dd72d1d465 176 def __str__(self):
borlanic 0:02dd72d1d465 177 """Return the string representation of this configuration parameter
borlanic 0:02dd72d1d465 178
borlanic 0:02dd72d1d465 179 Arguments: None
borlanic 0:02dd72d1d465 180 """
borlanic 0:02dd72d1d465 181 if self.value is not None:
borlanic 0:02dd72d1d465 182 return '%s = %s (macro name: "%s")' % \
borlanic 0:02dd72d1d465 183 (self.name, self.value, self.macro_name)
borlanic 0:02dd72d1d465 184 else:
borlanic 0:02dd72d1d465 185 return '%s has no value' % self.name
borlanic 0:02dd72d1d465 186
borlanic 0:02dd72d1d465 187 def get_verbose_description(self):
borlanic 0:02dd72d1d465 188 """Return a verbose description of this configuration parameter as a
borlanic 0:02dd72d1d465 189 string
borlanic 0:02dd72d1d465 190
borlanic 0:02dd72d1d465 191 Arguments: None
borlanic 0:02dd72d1d465 192 """
borlanic 0:02dd72d1d465 193 desc = "Name: %s%s\n" % \
borlanic 0:02dd72d1d465 194 (self.name, " (required parameter)" if self.required else "")
borlanic 0:02dd72d1d465 195 if self.help_text:
borlanic 0:02dd72d1d465 196 desc += " Description: %s\n" % self.help_text
borlanic 0:02dd72d1d465 197 desc += " Defined by: %s\n" % self.defined_by
borlanic 0:02dd72d1d465 198 if not self.value:
borlanic 0:02dd72d1d465 199 return desc + " No value set"
borlanic 0:02dd72d1d465 200 desc += " Macro name: %s\n" % self.macro_name
borlanic 0:02dd72d1d465 201 desc += " Value: %s (set by %s)" % (self.value, self.set_by)
borlanic 0:02dd72d1d465 202 return desc
borlanic 0:02dd72d1d465 203
borlanic 0:02dd72d1d465 204 class ConfigMacro(object):
borlanic 0:02dd72d1d465 205 """ A representation of a configuration macro. It handles both macros
borlanic 0:02dd72d1d465 206 without a value (MACRO) and with a value (MACRO=VALUE)
borlanic 0:02dd72d1d465 207 """
borlanic 0:02dd72d1d465 208 def __init__(self, name, unit_name, unit_kind):
borlanic 0:02dd72d1d465 209 """Construct a ConfigMacro object
borlanic 0:02dd72d1d465 210
borlanic 0:02dd72d1d465 211 Positional arguments:
borlanic 0:02dd72d1d465 212 name - the macro's name
borlanic 0:02dd72d1d465 213 unit_name - the location where the macro was defined
borlanic 0:02dd72d1d465 214 unit_kind - the type of macro this is
borlanic 0:02dd72d1d465 215 """
borlanic 0:02dd72d1d465 216 self.name = name
borlanic 0:02dd72d1d465 217 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
borlanic 0:02dd72d1d465 218 if name.find("=") != -1:
borlanic 0:02dd72d1d465 219 tmp = name.split("=")
borlanic 0:02dd72d1d465 220 if len(tmp) != 2:
borlanic 0:02dd72d1d465 221 raise ValueError("Invalid macro definition '%s' in '%s'" %
borlanic 0:02dd72d1d465 222 (name, self.defined_by))
borlanic 0:02dd72d1d465 223 self.macro_name = tmp[0]
borlanic 0:02dd72d1d465 224 self.macro_value = tmp[1]
borlanic 0:02dd72d1d465 225 else:
borlanic 0:02dd72d1d465 226 self.macro_name = name
borlanic 0:02dd72d1d465 227 self.macro_value = None
borlanic 0:02dd72d1d465 228
borlanic 0:02dd72d1d465 229 class ConfigCumulativeOverride(object):
borlanic 0:02dd72d1d465 230 """Representation of overrides for cumulative attributes"""
borlanic 0:02dd72d1d465 231 def __init__(self, name, additions=None, removals=None, strict=False):
borlanic 0:02dd72d1d465 232 """Construct a ConfigCumulativeOverride object
borlanic 0:02dd72d1d465 233
borlanic 0:02dd72d1d465 234 Positional arguments:
borlanic 0:02dd72d1d465 235 name - the name of the config file this came from ?
borlanic 0:02dd72d1d465 236
borlanic 0:02dd72d1d465 237 Keyword arguments:
borlanic 0:02dd72d1d465 238 additions - macros to add to the overrides
borlanic 0:02dd72d1d465 239 removals - macros to remove from the overrides
borlanic 0:02dd72d1d465 240 strict - Boolean indicating that attempting to remove from an override
borlanic 0:02dd72d1d465 241 that does not exist should error
borlanic 0:02dd72d1d465 242 """
borlanic 0:02dd72d1d465 243 self.name = name
borlanic 0:02dd72d1d465 244 if additions:
borlanic 0:02dd72d1d465 245 self.additions = set(additions)
borlanic 0:02dd72d1d465 246 else:
borlanic 0:02dd72d1d465 247 self.additions = set()
borlanic 0:02dd72d1d465 248 if removals:
borlanic 0:02dd72d1d465 249 self.removals = set(removals)
borlanic 0:02dd72d1d465 250 else:
borlanic 0:02dd72d1d465 251 self.removals = set()
borlanic 0:02dd72d1d465 252 self.strict = strict
borlanic 0:02dd72d1d465 253
borlanic 0:02dd72d1d465 254 def remove_cumulative_overrides(self, overrides):
borlanic 0:02dd72d1d465 255 """Extend the list of override removals.
borlanic 0:02dd72d1d465 256
borlanic 0:02dd72d1d465 257 Positional arguments:
borlanic 0:02dd72d1d465 258 overrides - a list of names that, when the override is evaluated, will
borlanic 0:02dd72d1d465 259 be removed
borlanic 0:02dd72d1d465 260 """
borlanic 0:02dd72d1d465 261 for override in overrides:
borlanic 0:02dd72d1d465 262 if override in self.additions:
borlanic 0:02dd72d1d465 263 raise ConfigException(
borlanic 0:02dd72d1d465 264 "Configuration conflict. The %s %s both added and removed."
borlanic 0:02dd72d1d465 265 % (self.name[:-1], override))
borlanic 0:02dd72d1d465 266
borlanic 0:02dd72d1d465 267 self.removals |= set(overrides)
borlanic 0:02dd72d1d465 268
borlanic 0:02dd72d1d465 269 def add_cumulative_overrides(self, overrides):
borlanic 0:02dd72d1d465 270 """Extend the list of override additions.
borlanic 0:02dd72d1d465 271
borlanic 0:02dd72d1d465 272 Positional arguments:
borlanic 0:02dd72d1d465 273 overrides - a list of a names that, when the override is evaluated, will
borlanic 0:02dd72d1d465 274 be added to the list
borlanic 0:02dd72d1d465 275 """
borlanic 0:02dd72d1d465 276 for override in overrides:
borlanic 0:02dd72d1d465 277 if override in self.removals or \
borlanic 0:02dd72d1d465 278 (self.strict and override not in self.additions):
borlanic 0:02dd72d1d465 279 raise ConfigException(
borlanic 0:02dd72d1d465 280 "Configuration conflict. The %s %s both added and removed."
borlanic 0:02dd72d1d465 281 % (self.name[:-1], override))
borlanic 0:02dd72d1d465 282
borlanic 0:02dd72d1d465 283 self.additions |= set(overrides)
borlanic 0:02dd72d1d465 284
borlanic 0:02dd72d1d465 285 def strict_cumulative_overrides(self, overrides):
borlanic 0:02dd72d1d465 286 """Remove all overrides that are not the specified ones
borlanic 0:02dd72d1d465 287
borlanic 0:02dd72d1d465 288 Positional arguments:
borlanic 0:02dd72d1d465 289 overrides - a list of names that will replace the entire attribute when
borlanic 0:02dd72d1d465 290 this override is evaluated.
borlanic 0:02dd72d1d465 291 """
borlanic 0:02dd72d1d465 292 self.remove_cumulative_overrides(self.additions - set(overrides))
borlanic 0:02dd72d1d465 293 self.add_cumulative_overrides(overrides)
borlanic 0:02dd72d1d465 294 self.strict = True
borlanic 0:02dd72d1d465 295
borlanic 0:02dd72d1d465 296 def update_target(self, target):
borlanic 0:02dd72d1d465 297 """Update the attributes of a target based on this override"""
borlanic 0:02dd72d1d465 298 setattr(target, self.name,
borlanic 0:02dd72d1d465 299 list((set(getattr(target, self.name, []))
borlanic 0:02dd72d1d465 300 | self.additions) - self.removals))
borlanic 0:02dd72d1d465 301
borlanic 0:02dd72d1d465 302
borlanic 0:02dd72d1d465 303 def _process_config_parameters(data, params, unit_name, unit_kind):
borlanic 0:02dd72d1d465 304 """Process a "config_parameters" section in either a target, a library,
borlanic 0:02dd72d1d465 305 or the application.
borlanic 0:02dd72d1d465 306
borlanic 0:02dd72d1d465 307 Positional arguments:
borlanic 0:02dd72d1d465 308 data - a dictionary with the configuration parameters
borlanic 0:02dd72d1d465 309 params - storage for the discovered configuration parameters
borlanic 0:02dd72d1d465 310 unit_name - the unit (target/library/application) that defines this
borlanic 0:02dd72d1d465 311 parameter
borlanic 0:02dd72d1d465 312 unit_kind - the kind of the unit ("target", "library" or "application")
borlanic 0:02dd72d1d465 313 """
borlanic 0:02dd72d1d465 314 for name, val in data.items():
borlanic 0:02dd72d1d465 315 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
borlanic 0:02dd72d1d465 316 # If the parameter was already defined, raise an error
borlanic 0:02dd72d1d465 317 if full_name in params:
borlanic 0:02dd72d1d465 318 raise ConfigException(
borlanic 0:02dd72d1d465 319 "Parameter name '%s' defined in both '%s' and '%s'" %
borlanic 0:02dd72d1d465 320 (name, ConfigParameter.get_display_name(unit_name, unit_kind),
borlanic 0:02dd72d1d465 321 params[full_name].defined_by))
borlanic 0:02dd72d1d465 322 # Otherwise add it to the list of known parameters
borlanic 0:02dd72d1d465 323 # If "val" is not a dictionary, this is a shortcut definition,
borlanic 0:02dd72d1d465 324 # otherwise it is a full definition
borlanic 0:02dd72d1d465 325 params[full_name] = ConfigParameter(name, val if isinstance(val, dict)
borlanic 0:02dd72d1d465 326 else {"value": val}, unit_name,
borlanic 0:02dd72d1d465 327 unit_kind)
borlanic 0:02dd72d1d465 328 return params
borlanic 0:02dd72d1d465 329
borlanic 0:02dd72d1d465 330
borlanic 0:02dd72d1d465 331 def _process_macros(mlist, macros, unit_name, unit_kind):
borlanic 0:02dd72d1d465 332 """Process a macro definition and check for incompatible duplicate
borlanic 0:02dd72d1d465 333 definitions.
borlanic 0:02dd72d1d465 334
borlanic 0:02dd72d1d465 335 Positional arguments:
borlanic 0:02dd72d1d465 336 mlist - list of macro names to process
borlanic 0:02dd72d1d465 337 macros - dictionary with currently discovered macros
borlanic 0:02dd72d1d465 338 unit_name - the unit (library/application) that defines this macro
borlanic 0:02dd72d1d465 339 unit_kind - the kind of the unit ("library" or "application")
borlanic 0:02dd72d1d465 340 """
borlanic 0:02dd72d1d465 341 for mname in mlist:
borlanic 0:02dd72d1d465 342 macro = ConfigMacro(mname, unit_name, unit_kind)
borlanic 0:02dd72d1d465 343 if (macro.macro_name in macros) and \
borlanic 0:02dd72d1d465 344 (macros[macro.macro_name].name != mname):
borlanic 0:02dd72d1d465 345 # Found an incompatible definition of the macro in another module,
borlanic 0:02dd72d1d465 346 # so raise an error
borlanic 0:02dd72d1d465 347 full_unit_name = ConfigParameter.get_display_name(unit_name,
borlanic 0:02dd72d1d465 348 unit_kind)
borlanic 0:02dd72d1d465 349 raise ConfigException(
borlanic 0:02dd72d1d465 350 ("Macro '%s' defined in both '%s' and '%s'"
borlanic 0:02dd72d1d465 351 % (macro.macro_name, macros[macro.macro_name].defined_by,
borlanic 0:02dd72d1d465 352 full_unit_name)) +
borlanic 0:02dd72d1d465 353 " with incompatible values")
borlanic 0:02dd72d1d465 354 macros[macro.macro_name] = macro
borlanic 0:02dd72d1d465 355
borlanic 0:02dd72d1d465 356
borlanic 0:02dd72d1d465 357 Region = namedtuple("Region", "name start size active filename")
borlanic 0:02dd72d1d465 358
borlanic 0:02dd72d1d465 359 class Config(object):
borlanic 0:02dd72d1d465 360 """'Config' implements the mbed configuration mechanism"""
borlanic 0:02dd72d1d465 361
borlanic 0:02dd72d1d465 362 # Libraries and applications have different names for their configuration
borlanic 0:02dd72d1d465 363 # files
borlanic 0:02dd72d1d465 364 __mbed_app_config_name = "mbed_app.json"
borlanic 0:02dd72d1d465 365 __mbed_lib_config_name = "mbed_lib.json"
borlanic 0:02dd72d1d465 366
borlanic 0:02dd72d1d465 367 __unused_overrides = set(["target.bootloader_img", "target.restrict_size",
borlanic 0:02dd72d1d465 368 "target.mbed_app_start", "target.mbed_app_size"])
borlanic 0:02dd72d1d465 369
borlanic 0:02dd72d1d465 370 # Allowed features in configurations
borlanic 0:02dd72d1d465 371 __allowed_features = [
borlanic 0:02dd72d1d465 372 "UVISOR", "BLE", "CLIENT", "IPV4", "LWIP", "COMMON_PAL", "STORAGE", "NANOSTACK",
borlanic 0:02dd72d1d465 373 # Nanostack configurations
borlanic 0:02dd72d1d465 374 "LOWPAN_BORDER_ROUTER", "LOWPAN_HOST", "LOWPAN_ROUTER", "NANOSTACK_FULL", "THREAD_BORDER_ROUTER", "THREAD_END_DEVICE", "THREAD_ROUTER", "ETHERNET_HOST"
borlanic 0:02dd72d1d465 375 ]
borlanic 0:02dd72d1d465 376
borlanic 0:02dd72d1d465 377 @classmethod
borlanic 0:02dd72d1d465 378 def find_app_config(cls, top_level_dirs):
borlanic 0:02dd72d1d465 379 app_config_location = None
borlanic 0:02dd72d1d465 380 for directory in top_level_dirs:
borlanic 0:02dd72d1d465 381 full_path = os.path.join(directory, cls.__mbed_app_config_name)
borlanic 0:02dd72d1d465 382 if os.path.isfile(full_path):
borlanic 0:02dd72d1d465 383 if app_config_location is not None:
borlanic 0:02dd72d1d465 384 raise ConfigException("Duplicate '%s' file in '%s' and '%s'"
borlanic 0:02dd72d1d465 385 % (cls.__mbed_app_config_name,
borlanic 0:02dd72d1d465 386 cls.app_config_location, full_path))
borlanic 0:02dd72d1d465 387 else:
borlanic 0:02dd72d1d465 388 app_config_location = full_path
borlanic 0:02dd72d1d465 389 return app_config_location
borlanic 0:02dd72d1d465 390
borlanic 0:02dd72d1d465 391 def format_validation_error(self, error, path):
borlanic 0:02dd72d1d465 392 if error.context:
borlanic 0:02dd72d1d465 393 return self.format_validation_error(error.context[0], path)
borlanic 0:02dd72d1d465 394 else:
borlanic 0:02dd72d1d465 395 return "in {} element {}: {}".format(
borlanic 0:02dd72d1d465 396 path, str(".".join(str(p) for p in error.absolute_path)), error.message)
borlanic 0:02dd72d1d465 397
borlanic 0:02dd72d1d465 398 def __init__(self, tgt, top_level_dirs=None, app_config=None):
borlanic 0:02dd72d1d465 399 """Construct a mbed configuration
borlanic 0:02dd72d1d465 400
borlanic 0:02dd72d1d465 401 Positional arguments:
borlanic 0:02dd72d1d465 402 target - the name of the mbed target used for this configuration
borlanic 0:02dd72d1d465 403 instance
borlanic 0:02dd72d1d465 404
borlanic 0:02dd72d1d465 405 Keyword argumets:
borlanic 0:02dd72d1d465 406 top_level_dirs - a list of top level source directories (where
borlanic 0:02dd72d1d465 407 mbed_app_config.json could be found)
borlanic 0:02dd72d1d465 408 app_config - location of a chosen mbed_app.json file
borlanic 0:02dd72d1d465 409
borlanic 0:02dd72d1d465 410 NOTE: Construction of a Config object will look for the application
borlanic 0:02dd72d1d465 411 configuration file in top_level_dirs. If found once, it'll parse it.
borlanic 0:02dd72d1d465 412 top_level_dirs may be None (in this case, the constructor will not
borlanic 0:02dd72d1d465 413 search for a configuration file).
borlanic 0:02dd72d1d465 414 """
borlanic 0:02dd72d1d465 415 config_errors = []
borlanic 0:02dd72d1d465 416 self.app_config_location = app_config
borlanic 0:02dd72d1d465 417 if self.app_config_location is None and top_level_dirs:
borlanic 0:02dd72d1d465 418 self.app_config_location = self.find_app_config(top_level_dirs)
borlanic 0:02dd72d1d465 419 try:
borlanic 0:02dd72d1d465 420 self.app_config_data = json_file_to_dict(self.app_config_location) \
borlanic 0:02dd72d1d465 421 if self.app_config_location else {}
borlanic 0:02dd72d1d465 422 except ValueError as exc:
borlanic 0:02dd72d1d465 423 self.app_config_data = {}
borlanic 0:02dd72d1d465 424 config_errors.append(
borlanic 0:02dd72d1d465 425 ConfigException("Could not parse mbed app configuration from %s"
borlanic 0:02dd72d1d465 426 % self.app_config_location))
borlanic 0:02dd72d1d465 427
borlanic 0:02dd72d1d465 428
borlanic 0:02dd72d1d465 429 if self.app_config_location is not None:
borlanic 0:02dd72d1d465 430 # Validate the format of the JSON file based on schema_app.json
borlanic 0:02dd72d1d465 431 schema_root = os.path.dirname(os.path.abspath(__file__))
borlanic 0:02dd72d1d465 432 schema_path = os.path.join(schema_root, "schema_app.json")
borlanic 0:02dd72d1d465 433 schema = json_file_to_dict(schema_path)
borlanic 0:02dd72d1d465 434
borlanic 0:02dd72d1d465 435 url = moves.urllib.request.pathname2url(schema_path)
borlanic 0:02dd72d1d465 436 uri = moves.urllib_parse.urljoin("file://", url)
borlanic 0:02dd72d1d465 437
borlanic 0:02dd72d1d465 438 resolver = RefResolver(uri, schema)
borlanic 0:02dd72d1d465 439 validator = Draft4Validator(schema, resolver=resolver)
borlanic 0:02dd72d1d465 440
borlanic 0:02dd72d1d465 441 errors = sorted(validator.iter_errors(self.app_config_data))
borlanic 0:02dd72d1d465 442
borlanic 0:02dd72d1d465 443 if errors:
borlanic 0:02dd72d1d465 444 raise ConfigException("; ".join(
borlanic 0:02dd72d1d465 445 self.format_validation_error(x, self.app_config_location)
borlanic 0:02dd72d1d465 446 for x in errors))
borlanic 0:02dd72d1d465 447
borlanic 0:02dd72d1d465 448 # Update the list of targets with the ones defined in the application
borlanic 0:02dd72d1d465 449 # config, if applicable
borlanic 0:02dd72d1d465 450 self.lib_config_data = {}
borlanic 0:02dd72d1d465 451 # Make sure that each config is processed only once
borlanic 0:02dd72d1d465 452 self.processed_configs = {}
borlanic 0:02dd72d1d465 453 if isinstance(tgt, Target):
borlanic 0:02dd72d1d465 454 self.target = tgt
borlanic 0:02dd72d1d465 455 else:
borlanic 0:02dd72d1d465 456 if tgt in TARGET_MAP:
borlanic 0:02dd72d1d465 457 self.target = TARGET_MAP[tgt]
borlanic 0:02dd72d1d465 458 else:
borlanic 0:02dd72d1d465 459 self.target = generate_py_target(
borlanic 0:02dd72d1d465 460 self.app_config_data.get("custom_targets", {}), tgt)
borlanic 0:02dd72d1d465 461 self.target = deepcopy(self.target)
borlanic 0:02dd72d1d465 462 self.target_labels = self.target.labels
borlanic 0:02dd72d1d465 463 for override in BOOTLOADER_OVERRIDES:
borlanic 0:02dd72d1d465 464 _, attr = override.split(".")
borlanic 0:02dd72d1d465 465 setattr(self.target, attr, None)
borlanic 0:02dd72d1d465 466
borlanic 0:02dd72d1d465 467 self.cumulative_overrides = {key: ConfigCumulativeOverride(key)
borlanic 0:02dd72d1d465 468 for key in CUMULATIVE_ATTRIBUTES}
borlanic 0:02dd72d1d465 469
borlanic 0:02dd72d1d465 470 self._process_config_and_overrides(self.app_config_data, {}, "app",
borlanic 0:02dd72d1d465 471 "application")
borlanic 0:02dd72d1d465 472 self.config_errors = config_errors
borlanic 0:02dd72d1d465 473
borlanic 0:02dd72d1d465 474 def add_config_files(self, flist):
borlanic 0:02dd72d1d465 475 """Add configuration files
borlanic 0:02dd72d1d465 476
borlanic 0:02dd72d1d465 477 Positional arguments:
borlanic 0:02dd72d1d465 478 flist - a list of files to add to this configuration
borlanic 0:02dd72d1d465 479 """
borlanic 0:02dd72d1d465 480 for config_file in flist:
borlanic 0:02dd72d1d465 481 if not config_file.endswith(self.__mbed_lib_config_name):
borlanic 0:02dd72d1d465 482 continue
borlanic 0:02dd72d1d465 483 full_path = os.path.normpath(os.path.abspath(config_file))
borlanic 0:02dd72d1d465 484 # Check that we didn't already process this file
borlanic 0:02dd72d1d465 485 if full_path in self.processed_configs:
borlanic 0:02dd72d1d465 486 continue
borlanic 0:02dd72d1d465 487 self.processed_configs[full_path] = True
borlanic 0:02dd72d1d465 488 # Read the library configuration and add a "__full_config_path"
borlanic 0:02dd72d1d465 489 # attribute to it
borlanic 0:02dd72d1d465 490 try:
borlanic 0:02dd72d1d465 491 cfg = json_file_to_dict(config_file)
borlanic 0:02dd72d1d465 492 except ValueError as exc:
borlanic 0:02dd72d1d465 493 raise ConfigException(str(exc))
borlanic 0:02dd72d1d465 494
borlanic 0:02dd72d1d465 495 # Validate the format of the JSON file based on the schema_lib.json
borlanic 0:02dd72d1d465 496 schema_root = os.path.dirname(os.path.abspath(__file__))
borlanic 0:02dd72d1d465 497 schema_path = os.path.join(schema_root, "schema_lib.json")
borlanic 0:02dd72d1d465 498 schema_file = json_file_to_dict(schema_path)
borlanic 0:02dd72d1d465 499
borlanic 0:02dd72d1d465 500 url = moves.urllib.request.pathname2url(schema_path)
borlanic 0:02dd72d1d465 501 uri = moves.urllib_parse.urljoin("file://", url)
borlanic 0:02dd72d1d465 502
borlanic 0:02dd72d1d465 503 resolver = RefResolver(uri, schema_file)
borlanic 0:02dd72d1d465 504 validator = Draft4Validator(schema_file, resolver=resolver)
borlanic 0:02dd72d1d465 505
borlanic 0:02dd72d1d465 506 errors = sorted(validator.iter_errors(cfg))
borlanic 0:02dd72d1d465 507
borlanic 0:02dd72d1d465 508 if errors:
borlanic 0:02dd72d1d465 509 raise ConfigException("; ".join(
borlanic 0:02dd72d1d465 510 self.format_validation_error(x, config_file)
borlanic 0:02dd72d1d465 511 for x in errors))
borlanic 0:02dd72d1d465 512
borlanic 0:02dd72d1d465 513 cfg["__config_path"] = full_path
borlanic 0:02dd72d1d465 514
borlanic 0:02dd72d1d465 515 # If there's already a configuration for a module with the same
borlanic 0:02dd72d1d465 516 # name, exit with error
borlanic 0:02dd72d1d465 517 if cfg["name"] in self.lib_config_data:
borlanic 0:02dd72d1d465 518 raise ConfigException(
borlanic 0:02dd72d1d465 519 "Library name '%s' is not unique (defined in '%s' and '%s')"
borlanic 0:02dd72d1d465 520 % (cfg["name"], full_path,
borlanic 0:02dd72d1d465 521 self.lib_config_data[cfg["name"]]["__config_path"]))
borlanic 0:02dd72d1d465 522 self.lib_config_data[cfg["name"]] = cfg
borlanic 0:02dd72d1d465 523
borlanic 0:02dd72d1d465 524 @property
borlanic 0:02dd72d1d465 525 def has_regions(self):
borlanic 0:02dd72d1d465 526 """Does this config have regions defined?"""
borlanic 0:02dd72d1d465 527 for override in BOOTLOADER_OVERRIDES:
borlanic 0:02dd72d1d465 528 _, attr = override.split(".")
borlanic 0:02dd72d1d465 529 if getattr(self.target, attr, None):
borlanic 0:02dd72d1d465 530 return True
borlanic 0:02dd72d1d465 531 return False
borlanic 0:02dd72d1d465 532
borlanic 0:02dd72d1d465 533 @property
borlanic 0:02dd72d1d465 534 def sectors(self):
borlanic 0:02dd72d1d465 535 """Return a list of tuples of sector start,size"""
borlanic 0:02dd72d1d465 536 cache = Cache(False, False)
borlanic 0:02dd72d1d465 537 if self.target.device_name not in cache.index:
borlanic 0:02dd72d1d465 538 raise ConfigException("Bootloader not supported on this target: "
borlanic 0:02dd72d1d465 539 "targets.json `device_name` not found in "
borlanic 0:02dd72d1d465 540 "arm_pack_manager index.")
borlanic 0:02dd72d1d465 541 cmsis_part = cache.index[self.target.device_name]
borlanic 0:02dd72d1d465 542 sectors = cmsis_part['sectors']
borlanic 0:02dd72d1d465 543 if sectors:
borlanic 0:02dd72d1d465 544 return sectors
borlanic 0:02dd72d1d465 545 raise ConfigException("No sector info available")
borlanic 0:02dd72d1d465 546
borlanic 0:02dd72d1d465 547 @property
borlanic 0:02dd72d1d465 548 def regions(self):
borlanic 0:02dd72d1d465 549 """Generate a list of regions from the config"""
borlanic 0:02dd72d1d465 550 if not self.target.bootloader_supported:
borlanic 0:02dd72d1d465 551 raise ConfigException("Bootloader not supported on this target.")
borlanic 0:02dd72d1d465 552 if not hasattr(self.target, "device_name"):
borlanic 0:02dd72d1d465 553 raise ConfigException("Bootloader not supported on this target: "
borlanic 0:02dd72d1d465 554 "targets.json `device_name` not specified.")
borlanic 0:02dd72d1d465 555 cache = Cache(False, False)
borlanic 0:02dd72d1d465 556 if self.target.device_name not in cache.index:
borlanic 0:02dd72d1d465 557 raise ConfigException("Bootloader not supported on this target: "
borlanic 0:02dd72d1d465 558 "targets.json `device_name` not found in "
borlanic 0:02dd72d1d465 559 "arm_pack_manager index.")
borlanic 0:02dd72d1d465 560 cmsis_part = cache.index[self.target.device_name]
borlanic 0:02dd72d1d465 561 if ((self.target.bootloader_img or self.target.restrict_size) and
borlanic 0:02dd72d1d465 562 (self.target.mbed_app_start or self.target.mbed_app_size)):
borlanic 0:02dd72d1d465 563 raise ConfigException(
borlanic 0:02dd72d1d465 564 "target.bootloader_img and target.restirct_size are "
borlanic 0:02dd72d1d465 565 "incompatible with target.mbed_app_start and "
borlanic 0:02dd72d1d465 566 "target.mbed_app_size")
borlanic 0:02dd72d1d465 567 try:
borlanic 0:02dd72d1d465 568 rom_size = int(cmsis_part['memory']['IROM1']['size'], 0)
borlanic 0:02dd72d1d465 569 rom_start = int(cmsis_part['memory']['IROM1']['start'], 0)
borlanic 0:02dd72d1d465 570 except KeyError:
borlanic 0:02dd72d1d465 571 try:
borlanic 0:02dd72d1d465 572 rom_size = int(cmsis_part['memory']['PROGRAM_FLASH']['size'], 0)
borlanic 0:02dd72d1d465 573 rom_start = int(cmsis_part['memory']['PROGRAM_FLASH']['start'], 0)
borlanic 0:02dd72d1d465 574 except KeyError:
borlanic 0:02dd72d1d465 575 raise ConfigException("Not enough information in CMSIS packs to "
borlanic 0:02dd72d1d465 576 "build a bootloader project")
borlanic 0:02dd72d1d465 577 if self.target.bootloader_img or self.target.restrict_size:
borlanic 0:02dd72d1d465 578 return self._generate_bootloader_build(rom_start, rom_size)
borlanic 0:02dd72d1d465 579 elif self.target.mbed_app_start or self.target.mbed_app_size:
borlanic 0:02dd72d1d465 580 return self._generate_linker_overrides(rom_start, rom_size)
borlanic 0:02dd72d1d465 581 else:
borlanic 0:02dd72d1d465 582 raise ConfigException(
borlanic 0:02dd72d1d465 583 "Bootloader build requested but no bootlader configuration")
borlanic 0:02dd72d1d465 584
borlanic 0:02dd72d1d465 585 @staticmethod
borlanic 0:02dd72d1d465 586 def header_member_size(member):
borlanic 0:02dd72d1d465 587 _, _, subtype, _ = member
borlanic 0:02dd72d1d465 588 try:
borlanic 0:02dd72d1d465 589 return int(subtype[:-2]) // 8
borlanic 0:02dd72d1d465 590 except:
borlanic 0:02dd72d1d465 591 if subtype.startswith("CRCITT32"):
borlanic 0:02dd72d1d465 592 return 32 // 8
borlanic 0:02dd72d1d465 593 elif subtype == "SHA256":
borlanic 0:02dd72d1d465 594 return 256 // 8
borlanic 0:02dd72d1d465 595 elif subtype == "SHA512":
borlanic 0:02dd72d1d465 596 return 512 // 8
borlanic 0:02dd72d1d465 597 else:
borlanic 0:02dd72d1d465 598 raise ValueError("target.header_format: subtype %s is not "
borlanic 0:02dd72d1d465 599 "understood" % subtype)
borlanic 0:02dd72d1d465 600
borlanic 0:02dd72d1d465 601 @staticmethod
borlanic 0:02dd72d1d465 602 def _header_size(format):
borlanic 0:02dd72d1d465 603 return sum(Config.header_member_size(m) for m in format)
borlanic 0:02dd72d1d465 604
borlanic 0:02dd72d1d465 605 def _make_header_region(self, start, header_format, offset=None):
borlanic 0:02dd72d1d465 606 size = self._header_size(header_format)
borlanic 0:02dd72d1d465 607 region = Region("header", start, size, False, None)
borlanic 0:02dd72d1d465 608 start += size
borlanic 0:02dd72d1d465 609 start = ((start + 7) // 8) * 8
borlanic 0:02dd72d1d465 610 return (start, region)
borlanic 0:02dd72d1d465 611
borlanic 0:02dd72d1d465 612 @staticmethod
borlanic 0:02dd72d1d465 613 def _assign_new_offset(rom_start, start, new_offset, region_name):
borlanic 0:02dd72d1d465 614 newstart = rom_start + integer(new_offset, 0)
borlanic 0:02dd72d1d465 615 if newstart < start:
borlanic 0:02dd72d1d465 616 raise ConfigException(
borlanic 0:02dd72d1d465 617 "Can not place % region inside previous region" % region_name)
borlanic 0:02dd72d1d465 618 return newstart
borlanic 0:02dd72d1d465 619
borlanic 0:02dd72d1d465 620 def _generate_bootloader_build(self, rom_start, rom_size):
borlanic 0:02dd72d1d465 621 start = rom_start
borlanic 0:02dd72d1d465 622 rom_end = rom_start + rom_size
borlanic 0:02dd72d1d465 623 if self.target.bootloader_img:
borlanic 0:02dd72d1d465 624 if isabs(self.target.bootloader_img):
borlanic 0:02dd72d1d465 625 filename = self.target.bootloader_img
borlanic 0:02dd72d1d465 626 else:
borlanic 0:02dd72d1d465 627 basedir = abspath(dirname(self.app_config_location))
borlanic 0:02dd72d1d465 628 filename = join(basedir, self.target.bootloader_img)
borlanic 0:02dd72d1d465 629 if not exists(filename):
borlanic 0:02dd72d1d465 630 raise ConfigException("Bootloader %s not found" % filename)
borlanic 0:02dd72d1d465 631 part = intelhex_offset(filename, offset=rom_start)
borlanic 0:02dd72d1d465 632 if part.minaddr() != rom_start:
borlanic 0:02dd72d1d465 633 raise ConfigException("bootloader executable does not "
borlanic 0:02dd72d1d465 634 "start at 0x%x" % rom_start)
borlanic 0:02dd72d1d465 635 part_size = (part.maxaddr() - part.minaddr()) + 1
borlanic 0:02dd72d1d465 636 part_size = Config._align_ceiling(rom_start + part_size, self.sectors) - rom_start
borlanic 0:02dd72d1d465 637 yield Region("bootloader", rom_start, part_size, False,
borlanic 0:02dd72d1d465 638 filename)
borlanic 0:02dd72d1d465 639 start = rom_start + part_size
borlanic 0:02dd72d1d465 640 if self.target.header_format:
borlanic 0:02dd72d1d465 641 if self.target.header_offset:
borlanic 0:02dd72d1d465 642 start = self._assign_new_offset(
borlanic 0:02dd72d1d465 643 rom_start, start, self.target.header_offset, "header")
borlanic 0:02dd72d1d465 644 start, region = self._make_header_region(
borlanic 0:02dd72d1d465 645 start, self.target.header_format)
borlanic 0:02dd72d1d465 646 yield region._replace(filename=self.target.header_format)
borlanic 0:02dd72d1d465 647 if self.target.restrict_size is not None:
borlanic 0:02dd72d1d465 648 new_size = int(self.target.restrict_size, 0)
borlanic 0:02dd72d1d465 649 new_size = Config._align_floor(start + new_size, self.sectors) - start
borlanic 0:02dd72d1d465 650 yield Region("application", start, new_size, True, None)
borlanic 0:02dd72d1d465 651 start += new_size
borlanic 0:02dd72d1d465 652 if self.target.header_format:
borlanic 0:02dd72d1d465 653 if self.target.header_offset:
borlanic 0:02dd72d1d465 654 start = self._assign_new_offset(
borlanic 0:02dd72d1d465 655 rom_start, start, self.target.header_offset, "header")
borlanic 0:02dd72d1d465 656 start, region = self._make_header_region(
borlanic 0:02dd72d1d465 657 start, self.target.header_format)
borlanic 0:02dd72d1d465 658 yield region
borlanic 0:02dd72d1d465 659 if self.target.app_offset:
borlanic 0:02dd72d1d465 660 start = self._assign_new_offset(
borlanic 0:02dd72d1d465 661 rom_start, start, self.target.app_offset, "application")
borlanic 0:02dd72d1d465 662 yield Region("post_application", start, rom_end - start,
borlanic 0:02dd72d1d465 663 False, None)
borlanic 0:02dd72d1d465 664 else:
borlanic 0:02dd72d1d465 665 if self.target.app_offset:
borlanic 0:02dd72d1d465 666 start = self._assign_new_offset(
borlanic 0:02dd72d1d465 667 rom_start, start, self.target.app_offset, "application")
borlanic 0:02dd72d1d465 668 yield Region("application", start, rom_end - start,
borlanic 0:02dd72d1d465 669 True, None)
borlanic 0:02dd72d1d465 670 if start > rom_start + rom_size:
borlanic 0:02dd72d1d465 671 raise ConfigException("Not enough memory on device to fit all "
borlanic 0:02dd72d1d465 672 "application regions")
borlanic 0:02dd72d1d465 673
borlanic 0:02dd72d1d465 674 @staticmethod
borlanic 0:02dd72d1d465 675 def _find_sector(address, sectors):
borlanic 0:02dd72d1d465 676 target_size = -1
borlanic 0:02dd72d1d465 677 target_start = -1
borlanic 0:02dd72d1d465 678 for (start, size) in sectors:
borlanic 0:02dd72d1d465 679 if address < start:
borlanic 0:02dd72d1d465 680 break
borlanic 0:02dd72d1d465 681 target_start = start
borlanic 0:02dd72d1d465 682 target_size = size
borlanic 0:02dd72d1d465 683 if (target_size < 0):
borlanic 0:02dd72d1d465 684 raise ConfigException("No valid sector found")
borlanic 0:02dd72d1d465 685 return target_start, target_size
borlanic 0:02dd72d1d465 686
borlanic 0:02dd72d1d465 687 @staticmethod
borlanic 0:02dd72d1d465 688 def _align_floor(address, sectors):
borlanic 0:02dd72d1d465 689 target_start, target_size = Config._find_sector(address, sectors)
borlanic 0:02dd72d1d465 690 sector_num = (address - target_start) // target_size
borlanic 0:02dd72d1d465 691 return target_start + (sector_num * target_size)
borlanic 0:02dd72d1d465 692
borlanic 0:02dd72d1d465 693 @staticmethod
borlanic 0:02dd72d1d465 694 def _align_ceiling(address, sectors):
borlanic 0:02dd72d1d465 695 target_start, target_size = Config._find_sector(address, sectors)
borlanic 0:02dd72d1d465 696 sector_num = ((address - target_start) + target_size - 1) // target_size
borlanic 0:02dd72d1d465 697 return target_start + (sector_num * target_size)
borlanic 0:02dd72d1d465 698
borlanic 0:02dd72d1d465 699 @property
borlanic 0:02dd72d1d465 700 def report(self):
borlanic 0:02dd72d1d465 701 return {'app_config': self.app_config_location,
borlanic 0:02dd72d1d465 702 'library_configs': map(relpath, self.processed_configs.keys())}
borlanic 0:02dd72d1d465 703
borlanic 0:02dd72d1d465 704 def _generate_linker_overrides(self, rom_start, rom_size):
borlanic 0:02dd72d1d465 705 if self.target.mbed_app_start is not None:
borlanic 0:02dd72d1d465 706 start = int(self.target.mbed_app_start, 0)
borlanic 0:02dd72d1d465 707 else:
borlanic 0:02dd72d1d465 708 start = rom_start
borlanic 0:02dd72d1d465 709 if self.target.mbed_app_size is not None:
borlanic 0:02dd72d1d465 710 size = int(self.target.mbed_app_size, 0)
borlanic 0:02dd72d1d465 711 else:
borlanic 0:02dd72d1d465 712 size = (rom_size + rom_start) - start
borlanic 0:02dd72d1d465 713 if start < rom_start:
borlanic 0:02dd72d1d465 714 raise ConfigException("Application starts before ROM")
borlanic 0:02dd72d1d465 715 if size + start > rom_size + rom_start:
borlanic 0:02dd72d1d465 716 raise ConfigException("Application ends after ROM")
borlanic 0:02dd72d1d465 717 yield Region("application", start, size, True, None)
borlanic 0:02dd72d1d465 718
borlanic 0:02dd72d1d465 719 def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
borlanic 0:02dd72d1d465 720 """Process "config_parameters" and "target_config_overrides" into a
borlanic 0:02dd72d1d465 721 given dictionary
borlanic 0:02dd72d1d465 722
borlanic 0:02dd72d1d465 723 Positional arguments:
borlanic 0:02dd72d1d465 724 data - the configuration data of the library/appliation
borlanic 0:02dd72d1d465 725 params - storage for the discovered configuration parameters
borlanic 0:02dd72d1d465 726 unit_name - the unit (library/application) that defines this parameter
borlanic 0:02dd72d1d465 727 unit_kind - the kind of the unit ("library" or "application")
borlanic 0:02dd72d1d465 728 """
borlanic 0:02dd72d1d465 729 self.config_errors = []
borlanic 0:02dd72d1d465 730 _process_config_parameters(data.get("config", {}), params, unit_name,
borlanic 0:02dd72d1d465 731 unit_kind)
borlanic 0:02dd72d1d465 732 for label, overrides in data.get("target_overrides", {}).items():
borlanic 0:02dd72d1d465 733 # If the label is defined by the target or it has the special value
borlanic 0:02dd72d1d465 734 # "*", process the overrides
borlanic 0:02dd72d1d465 735 if (label == '*') or (label in self.target_labels):
borlanic 0:02dd72d1d465 736 # Check for invalid cumulative overrides in libraries
borlanic 0:02dd72d1d465 737 if (unit_kind == 'library' and
borlanic 0:02dd72d1d465 738 any(attr.startswith('target.extra_labels') for attr
borlanic 0:02dd72d1d465 739 in overrides.keys())):
borlanic 0:02dd72d1d465 740 raise ConfigException(
borlanic 0:02dd72d1d465 741 "Target override 'target.extra_labels' in " +
borlanic 0:02dd72d1d465 742 ConfigParameter.get_display_name(unit_name, unit_kind,
borlanic 0:02dd72d1d465 743 label) +
borlanic 0:02dd72d1d465 744 " is only allowed at the application level")
borlanic 0:02dd72d1d465 745
borlanic 0:02dd72d1d465 746 # Parse out cumulative overrides
borlanic 0:02dd72d1d465 747 for attr, cumulatives in self.cumulative_overrides.items():
borlanic 0:02dd72d1d465 748 if 'target.'+attr in overrides:
borlanic 0:02dd72d1d465 749 key = 'target.' + attr
borlanic 0:02dd72d1d465 750 if not isinstance(overrides[key], list):
borlanic 0:02dd72d1d465 751 raise ConfigException(
borlanic 0:02dd72d1d465 752 "The value of %s.%s is not of type %s" %
borlanic 0:02dd72d1d465 753 (unit_name, "target_overrides." + key,
borlanic 0:02dd72d1d465 754 "list"))
borlanic 0:02dd72d1d465 755 cumulatives.strict_cumulative_overrides(overrides[key])
borlanic 0:02dd72d1d465 756 del overrides[key]
borlanic 0:02dd72d1d465 757
borlanic 0:02dd72d1d465 758 if 'target.'+attr+'_add' in overrides:
borlanic 0:02dd72d1d465 759 key = 'target.' + attr + "_add"
borlanic 0:02dd72d1d465 760 if not isinstance(overrides[key], list):
borlanic 0:02dd72d1d465 761 raise ConfigException(
borlanic 0:02dd72d1d465 762 "The value of %s.%s is not of type %s" %
borlanic 0:02dd72d1d465 763 (unit_name, "target_overrides." + key,
borlanic 0:02dd72d1d465 764 "list"))
borlanic 0:02dd72d1d465 765 cumulatives.add_cumulative_overrides(overrides[key])
borlanic 0:02dd72d1d465 766 del overrides[key]
borlanic 0:02dd72d1d465 767
borlanic 0:02dd72d1d465 768 if 'target.'+attr+'_remove' in overrides:
borlanic 0:02dd72d1d465 769 key = 'target.' + attr + "_remove"
borlanic 0:02dd72d1d465 770 if not isinstance(overrides[key], list):
borlanic 0:02dd72d1d465 771 raise ConfigException(
borlanic 0:02dd72d1d465 772 "The value of %s.%s is not of type %s" %
borlanic 0:02dd72d1d465 773 (unit_name, "target_overrides." + key,
borlanic 0:02dd72d1d465 774 "list"))
borlanic 0:02dd72d1d465 775 cumulatives.remove_cumulative_overrides(overrides[key])
borlanic 0:02dd72d1d465 776 del overrides[key]
borlanic 0:02dd72d1d465 777
borlanic 0:02dd72d1d465 778 # Consider the others as overrides
borlanic 0:02dd72d1d465 779 for name, val in overrides.items():
borlanic 0:02dd72d1d465 780 if (name in PATH_OVERRIDES and "__config_path" in data):
borlanic 0:02dd72d1d465 781 val = os.path.join(
borlanic 0:02dd72d1d465 782 os.path.dirname(data["__config_path"]), val)
borlanic 0:02dd72d1d465 783
borlanic 0:02dd72d1d465 784 # Get the full name of the parameter
borlanic 0:02dd72d1d465 785 full_name = ConfigParameter.get_full_name(name, unit_name,
borlanic 0:02dd72d1d465 786 unit_kind, label)
borlanic 0:02dd72d1d465 787 if full_name in params:
borlanic 0:02dd72d1d465 788 params[full_name].set_value(val, unit_name, unit_kind,
borlanic 0:02dd72d1d465 789 label)
borlanic 0:02dd72d1d465 790 elif (name.startswith("target.") and
borlanic 0:02dd72d1d465 791 (unit_kind is "application" or
borlanic 0:02dd72d1d465 792 name in BOOTLOADER_OVERRIDES)):
borlanic 0:02dd72d1d465 793 _, attribute = name.split(".")
borlanic 0:02dd72d1d465 794 setattr(self.target, attribute, val)
borlanic 0:02dd72d1d465 795 continue
borlanic 0:02dd72d1d465 796 else:
borlanic 0:02dd72d1d465 797 self.config_errors.append(
borlanic 0:02dd72d1d465 798 ConfigException(
borlanic 0:02dd72d1d465 799 "Attempt to override undefined parameter" +
borlanic 0:02dd72d1d465 800 (" '%s' in '%s'"
borlanic 0:02dd72d1d465 801 % (full_name,
borlanic 0:02dd72d1d465 802 ConfigParameter.get_display_name(unit_name,
borlanic 0:02dd72d1d465 803 unit_kind,
borlanic 0:02dd72d1d465 804 label)))))
borlanic 0:02dd72d1d465 805
borlanic 0:02dd72d1d465 806 for cumulatives in self.cumulative_overrides.values():
borlanic 0:02dd72d1d465 807 cumulatives.update_target(self.target)
borlanic 0:02dd72d1d465 808
borlanic 0:02dd72d1d465 809 return params
borlanic 0:02dd72d1d465 810
borlanic 0:02dd72d1d465 811 def get_target_config_data(self):
borlanic 0:02dd72d1d465 812 """Read and interpret configuration data defined by targets.
borlanic 0:02dd72d1d465 813
borlanic 0:02dd72d1d465 814 We consider the resolution order for our target and sort it by level
borlanic 0:02dd72d1d465 815 reversed, so that we first look at the top level target (the parent),
borlanic 0:02dd72d1d465 816 then its direct children, then the children of those children and so on,
borlanic 0:02dd72d1d465 817 until we reach self.target
borlanic 0:02dd72d1d465 818 TODO: this might not work so well in some multiple inheritance scenarios
borlanic 0:02dd72d1d465 819 At each step, look at two keys of the target data:
borlanic 0:02dd72d1d465 820 - config_parameters: used to define new configuration parameters
borlanic 0:02dd72d1d465 821 - config_overrides: used to override already defined configuration
borlanic 0:02dd72d1d465 822 parameters
borlanic 0:02dd72d1d465 823
borlanic 0:02dd72d1d465 824 Arguments: None
borlanic 0:02dd72d1d465 825 """
borlanic 0:02dd72d1d465 826 params, json_data = {}, self.target.json_data
borlanic 0:02dd72d1d465 827 resolution_order = [e[0] for e
borlanic 0:02dd72d1d465 828 in sorted(
borlanic 0:02dd72d1d465 829 self.target.resolution_order,
borlanic 0:02dd72d1d465 830 key=lambda e: e[1], reverse=True)]
borlanic 0:02dd72d1d465 831 for tname in resolution_order:
borlanic 0:02dd72d1d465 832 # Read the target data directly from its description
borlanic 0:02dd72d1d465 833 target_data = json_data[tname]
borlanic 0:02dd72d1d465 834 # Process definitions first
borlanic 0:02dd72d1d465 835 _process_config_parameters(target_data.get("config", {}), params,
borlanic 0:02dd72d1d465 836 tname, "target")
borlanic 0:02dd72d1d465 837 # Then process overrides
borlanic 0:02dd72d1d465 838 for name, val in target_data.get("overrides", {}).items():
borlanic 0:02dd72d1d465 839 full_name = ConfigParameter.get_full_name(name, tname, "target")
borlanic 0:02dd72d1d465 840 # If the parameter name is not defined or if there isn't a path
borlanic 0:02dd72d1d465 841 # from this target to the target where the parameter was defined
borlanic 0:02dd72d1d465 842 # in the target inheritance tree, raise an error We need to use
borlanic 0:02dd72d1d465 843 # 'defined_by[7:]' to remove the "target:" prefix from
borlanic 0:02dd72d1d465 844 # defined_by
borlanic 0:02dd72d1d465 845 rel_names = [tgt for tgt, _ in
borlanic 0:02dd72d1d465 846 get_resolution_order(self.target.json_data, tname,
borlanic 0:02dd72d1d465 847 [])]
borlanic 0:02dd72d1d465 848 if full_name in BOOTLOADER_OVERRIDES:
borlanic 0:02dd72d1d465 849 continue
borlanic 0:02dd72d1d465 850 if (full_name not in params) or \
borlanic 0:02dd72d1d465 851 (params[full_name].defined_by[7:] not in rel_names):
borlanic 0:02dd72d1d465 852 raise ConfigException(
borlanic 0:02dd72d1d465 853 "Attempt to override undefined parameter '%s' in '%s'"
borlanic 0:02dd72d1d465 854 % (name,
borlanic 0:02dd72d1d465 855 ConfigParameter.get_display_name(tname, "target")))
borlanic 0:02dd72d1d465 856 # Otherwise update the value of the parameter
borlanic 0:02dd72d1d465 857 params[full_name].set_value(val, tname, "target")
borlanic 0:02dd72d1d465 858 return params
borlanic 0:02dd72d1d465 859
borlanic 0:02dd72d1d465 860 def get_lib_config_data(self):
borlanic 0:02dd72d1d465 861 """ Read and interpret configuration data defined by libraries. It is
borlanic 0:02dd72d1d465 862 assumed that "add_config_files" above was already called and the library
borlanic 0:02dd72d1d465 863 configuration data exists in self.lib_config_data
borlanic 0:02dd72d1d465 864
borlanic 0:02dd72d1d465 865 Arguments: None
borlanic 0:02dd72d1d465 866 """
borlanic 0:02dd72d1d465 867 all_params, macros = {}, {}
borlanic 0:02dd72d1d465 868 for lib_name, lib_data in self.lib_config_data.items():
borlanic 0:02dd72d1d465 869 all_params.update(self._process_config_and_overrides(lib_data, {},
borlanic 0:02dd72d1d465 870 lib_name,
borlanic 0:02dd72d1d465 871 "library"))
borlanic 0:02dd72d1d465 872 _process_macros(lib_data.get("macros", []), macros, lib_name,
borlanic 0:02dd72d1d465 873 "library")
borlanic 0:02dd72d1d465 874 return all_params, macros
borlanic 0:02dd72d1d465 875
borlanic 0:02dd72d1d465 876 def get_app_config_data(self, params, macros):
borlanic 0:02dd72d1d465 877 """ Read and interpret the configuration data defined by the target. The
borlanic 0:02dd72d1d465 878 target can override any configuration parameter, as well as define its
borlanic 0:02dd72d1d465 879 own configuration data.
borlanic 0:02dd72d1d465 880
borlanic 0:02dd72d1d465 881 Positional arguments.
borlanic 0:02dd72d1d465 882 params - the dictionary with configuration parameters found so far (in
borlanic 0:02dd72d1d465 883 the target and in libraries)
borlanic 0:02dd72d1d465 884 macros - the list of macros defined in the configuration
borlanic 0:02dd72d1d465 885 """
borlanic 0:02dd72d1d465 886 app_cfg = self.app_config_data
borlanic 0:02dd72d1d465 887 # The application can have a "config_parameters" and a
borlanic 0:02dd72d1d465 888 # "target_config_overrides" section just like a library
borlanic 0:02dd72d1d465 889 self._process_config_and_overrides(app_cfg, params, "app",
borlanic 0:02dd72d1d465 890 "application")
borlanic 0:02dd72d1d465 891 # The application can also defined macros
borlanic 0:02dd72d1d465 892 _process_macros(app_cfg.get("macros", []), macros, "app",
borlanic 0:02dd72d1d465 893 "application")
borlanic 0:02dd72d1d465 894
borlanic 0:02dd72d1d465 895 def get_config_data(self):
borlanic 0:02dd72d1d465 896 """ Return the configuration data in two parts: (params, macros)
borlanic 0:02dd72d1d465 897 params - a dictionary with mapping a name to a ConfigParam
borlanic 0:02dd72d1d465 898 macros - the list of macros defined with "macros" in libraries and in
borlanic 0:02dd72d1d465 899 the application (as ConfigMacro instances)
borlanic 0:02dd72d1d465 900
borlanic 0:02dd72d1d465 901 Arguments: None
borlanic 0:02dd72d1d465 902 """
borlanic 0:02dd72d1d465 903 all_params = self.get_target_config_data()
borlanic 0:02dd72d1d465 904 lib_params, macros = self.get_lib_config_data()
borlanic 0:02dd72d1d465 905 all_params.update(lib_params)
borlanic 0:02dd72d1d465 906 self.get_app_config_data(all_params, macros)
borlanic 0:02dd72d1d465 907 return all_params, macros
borlanic 0:02dd72d1d465 908
borlanic 0:02dd72d1d465 909 @staticmethod
borlanic 0:02dd72d1d465 910 def _check_required_parameters(params):
borlanic 0:02dd72d1d465 911 """Check that there are no required parameters without a value
borlanic 0:02dd72d1d465 912
borlanic 0:02dd72d1d465 913 Positional arguments:
borlanic 0:02dd72d1d465 914 params - the list of parameters to check
borlanic 0:02dd72d1d465 915
borlanic 0:02dd72d1d465 916 NOTE: This function does not return. Instead, it throws a
borlanic 0:02dd72d1d465 917 ConfigException when any of the required parameters are missing values
borlanic 0:02dd72d1d465 918 """
borlanic 0:02dd72d1d465 919 for param in params.values():
borlanic 0:02dd72d1d465 920 if param.required and (param.value is None):
borlanic 0:02dd72d1d465 921 raise ConfigException("Required parameter '" + param.name +
borlanic 0:02dd72d1d465 922 "' defined by '" + param.defined_by +
borlanic 0:02dd72d1d465 923 "' doesn't have a value")
borlanic 0:02dd72d1d465 924
borlanic 0:02dd72d1d465 925 @staticmethod
borlanic 0:02dd72d1d465 926 def parameters_to_macros(params):
borlanic 0:02dd72d1d465 927 """ Encode the configuration parameters as C macro definitions.
borlanic 0:02dd72d1d465 928
borlanic 0:02dd72d1d465 929 Positional arguments:
borlanic 0:02dd72d1d465 930 params - a dictionary mapping a name to a ConfigParameter
borlanic 0:02dd72d1d465 931
borlanic 0:02dd72d1d465 932 Return: a list of strings that encode the configuration parameters as
borlanic 0:02dd72d1d465 933 C pre-processor macros
borlanic 0:02dd72d1d465 934 """
borlanic 0:02dd72d1d465 935 return ['%s=%s' % (m.macro_name, m.value) for m in params.values()
borlanic 0:02dd72d1d465 936 if m.value is not None]
borlanic 0:02dd72d1d465 937
borlanic 0:02dd72d1d465 938 @staticmethod
borlanic 0:02dd72d1d465 939 def config_macros_to_macros(macros):
borlanic 0:02dd72d1d465 940 """ Return the macro definitions generated for a dictionary of
borlanic 0:02dd72d1d465 941 ConfigMacros (as returned by get_config_data).
borlanic 0:02dd72d1d465 942
borlanic 0:02dd72d1d465 943 Positional arguments:
borlanic 0:02dd72d1d465 944 params - a dictionary mapping a name to a ConfigMacro instance
borlanic 0:02dd72d1d465 945
borlanic 0:02dd72d1d465 946 Return: a list of strings that are the C pre-processor macros
borlanic 0:02dd72d1d465 947 """
borlanic 0:02dd72d1d465 948 return [m.name for m in macros.values()]
borlanic 0:02dd72d1d465 949
borlanic 0:02dd72d1d465 950 @staticmethod
borlanic 0:02dd72d1d465 951 def config_to_macros(config):
borlanic 0:02dd72d1d465 952 """Convert the configuration data to a list of C macros
borlanic 0:02dd72d1d465 953
borlanic 0:02dd72d1d465 954 Positional arguments:
borlanic 0:02dd72d1d465 955 config - configuration data as (ConfigParam instances, ConfigMacro
borlanic 0:02dd72d1d465 956 instances) tuple (as returned by get_config_data())
borlanic 0:02dd72d1d465 957 """
borlanic 0:02dd72d1d465 958 params, macros = config[0], config[1]
borlanic 0:02dd72d1d465 959 Config._check_required_parameters(params)
borlanic 0:02dd72d1d465 960 return Config.config_macros_to_macros(macros) + \
borlanic 0:02dd72d1d465 961 Config.parameters_to_macros(params)
borlanic 0:02dd72d1d465 962
borlanic 0:02dd72d1d465 963 def get_config_data_macros(self):
borlanic 0:02dd72d1d465 964 """ Convert a Config object to a list of C macros
borlanic 0:02dd72d1d465 965
borlanic 0:02dd72d1d465 966 Arguments: None
borlanic 0:02dd72d1d465 967 """
borlanic 0:02dd72d1d465 968 return self.config_to_macros(self.get_config_data())
borlanic 0:02dd72d1d465 969
borlanic 0:02dd72d1d465 970 def get_features(self):
borlanic 0:02dd72d1d465 971 """ Extract any features from the configuration data
borlanic 0:02dd72d1d465 972
borlanic 0:02dd72d1d465 973 Arguments: None
borlanic 0:02dd72d1d465 974 """
borlanic 0:02dd72d1d465 975 params, _ = self.get_config_data()
borlanic 0:02dd72d1d465 976 self._check_required_parameters(params)
borlanic 0:02dd72d1d465 977 self.cumulative_overrides['features']\
borlanic 0:02dd72d1d465 978 .update_target(self.target)
borlanic 0:02dd72d1d465 979
borlanic 0:02dd72d1d465 980 for feature in self.target.features:
borlanic 0:02dd72d1d465 981 if feature not in self.__allowed_features:
borlanic 0:02dd72d1d465 982 raise ConfigException(
borlanic 0:02dd72d1d465 983 "Feature '%s' is not a supported features" % feature)
borlanic 0:02dd72d1d465 984
borlanic 0:02dd72d1d465 985 return self.target.features
borlanic 0:02dd72d1d465 986
borlanic 0:02dd72d1d465 987 def validate_config(self):
borlanic 0:02dd72d1d465 988 """ Validate configuration settings. This either returns True or
borlanic 0:02dd72d1d465 989 raises an exception
borlanic 0:02dd72d1d465 990
borlanic 0:02dd72d1d465 991 Arguments: None
borlanic 0:02dd72d1d465 992 """
borlanic 0:02dd72d1d465 993 if self.config_errors:
borlanic 0:02dd72d1d465 994 raise self.config_errors[0]
borlanic 0:02dd72d1d465 995 return True
borlanic 0:02dd72d1d465 996
borlanic 0:02dd72d1d465 997
borlanic 0:02dd72d1d465 998 @property
borlanic 0:02dd72d1d465 999 def name(self):
borlanic 0:02dd72d1d465 1000 if "artifact_name" in self.app_config_data:
borlanic 0:02dd72d1d465 1001 return self.app_config_data["artifact_name"]
borlanic 0:02dd72d1d465 1002 else:
borlanic 0:02dd72d1d465 1003 return None
borlanic 0:02dd72d1d465 1004
borlanic 0:02dd72d1d465 1005 def load_resources(self, resources):
borlanic 0:02dd72d1d465 1006 """ Load configuration data from a Resources instance and expand it
borlanic 0:02dd72d1d465 1007 based on defined features.
borlanic 0:02dd72d1d465 1008
borlanic 0:02dd72d1d465 1009 Positional arguments:
borlanic 0:02dd72d1d465 1010 resources - the resources object to load from and expand
borlanic 0:02dd72d1d465 1011 """
borlanic 0:02dd72d1d465 1012 # Update configuration files until added features creates no changes
borlanic 0:02dd72d1d465 1013 prev_features = set()
borlanic 0:02dd72d1d465 1014 self.validate_config()
borlanic 0:02dd72d1d465 1015 while True:
borlanic 0:02dd72d1d465 1016 # Add/update the configuration with any .json files found while
borlanic 0:02dd72d1d465 1017 # scanning
borlanic 0:02dd72d1d465 1018 self.add_config_files(resources.json_files)
borlanic 0:02dd72d1d465 1019
borlanic 0:02dd72d1d465 1020 # Add features while we find new ones
borlanic 0:02dd72d1d465 1021 features = set(self.get_features())
borlanic 0:02dd72d1d465 1022 if features == prev_features:
borlanic 0:02dd72d1d465 1023 break
borlanic 0:02dd72d1d465 1024
borlanic 0:02dd72d1d465 1025 for feature in features:
borlanic 0:02dd72d1d465 1026 if feature in resources.features:
borlanic 0:02dd72d1d465 1027 resources.add(resources.features[feature])
borlanic 0:02dd72d1d465 1028
borlanic 0:02dd72d1d465 1029 prev_features = features
borlanic 0:02dd72d1d465 1030 self.validate_config()
borlanic 0:02dd72d1d465 1031
borlanic 0:02dd72d1d465 1032 if (hasattr(self.target, "release_versions") and
borlanic 0:02dd72d1d465 1033 "5" not in self.target.release_versions and
borlanic 0:02dd72d1d465 1034 "rtos" in self.lib_config_data):
borlanic 0:02dd72d1d465 1035 raise NotSupportedException("Target does not support mbed OS 5")
borlanic 0:02dd72d1d465 1036
borlanic 0:02dd72d1d465 1037 return resources
borlanic 0:02dd72d1d465 1038
borlanic 0:02dd72d1d465 1039 @staticmethod
borlanic 0:02dd72d1d465 1040 def config_to_header(config, fname=None):
borlanic 0:02dd72d1d465 1041 """ Convert the configuration data to the content of a C header file,
borlanic 0:02dd72d1d465 1042 meant to be included to a C/C++ file. The content is returned as a
borlanic 0:02dd72d1d465 1043 string.
borlanic 0:02dd72d1d465 1044
borlanic 0:02dd72d1d465 1045 Positional arguments:
borlanic 0:02dd72d1d465 1046 config - configuration data as (ConfigParam instances, ConfigMacro
borlanic 0:02dd72d1d465 1047 instances) tuple (as returned by get_config_data())
borlanic 0:02dd72d1d465 1048
borlanic 0:02dd72d1d465 1049 Keyword arguments:
borlanic 0:02dd72d1d465 1050 fname - also write the content is to the file called "fname".
borlanic 0:02dd72d1d465 1051 WARNING: if 'fname' names an existing file, it will be
borlanic 0:02dd72d1d465 1052 overwritten!
borlanic 0:02dd72d1d465 1053 """
borlanic 0:02dd72d1d465 1054 params, macros = config[0] or {}, config[1] or {}
borlanic 0:02dd72d1d465 1055 Config._check_required_parameters(params)
borlanic 0:02dd72d1d465 1056 params_with_values = [p for p in params.values() if p.value is not None]
borlanic 0:02dd72d1d465 1057 ctx = {
borlanic 0:02dd72d1d465 1058 "cfg_params" : [(p.macro_name, str(p.value), p.set_by)
borlanic 0:02dd72d1d465 1059 for p in params_with_values],
borlanic 0:02dd72d1d465 1060 "macros": [(m.macro_name, str(m.macro_value or ""), m.defined_by)
borlanic 0:02dd72d1d465 1061 for m in macros.values()],
borlanic 0:02dd72d1d465 1062 "name_len": max([len(m.macro_name) for m in macros.values()] +
borlanic 0:02dd72d1d465 1063 [len(m.macro_name) for m in params_with_values]
borlanic 0:02dd72d1d465 1064 + [0]),
borlanic 0:02dd72d1d465 1065 "val_len" : max([len(str(m.value)) for m in params_with_values] +
borlanic 0:02dd72d1d465 1066 [len(m.macro_value or "") for m in macros.values()]
borlanic 0:02dd72d1d465 1067 + [0]),
borlanic 0:02dd72d1d465 1068 }
borlanic 0:02dd72d1d465 1069 jinja_loader = FileSystemLoader(dirname(abspath(__file__)))
borlanic 0:02dd72d1d465 1070 jinja_environment = Environment(loader=jinja_loader,
borlanic 0:02dd72d1d465 1071 undefined=StrictUndefined)
borlanic 0:02dd72d1d465 1072 header_data = jinja_environment.get_template("header.tmpl").render(ctx)
borlanic 0:02dd72d1d465 1073 # If fname is given, write "header_data" to it
borlanic 0:02dd72d1d465 1074 if fname:
borlanic 0:02dd72d1d465 1075 with open(fname, "w+") as file_desc:
borlanic 0:02dd72d1d465 1076 file_desc.write(header_data)
borlanic 0:02dd72d1d465 1077 return header_data
borlanic 0:02dd72d1d465 1078
borlanic 0:02dd72d1d465 1079 def get_config_data_header(self, fname=None):
borlanic 0:02dd72d1d465 1080 """ Convert a Config instance to the content of a C header file, meant
borlanic 0:02dd72d1d465 1081 to be included to a C/C++ file. The content is returned as a string.
borlanic 0:02dd72d1d465 1082
borlanic 0:02dd72d1d465 1083 Keyword arguments:
borlanic 0:02dd72d1d465 1084 fname - also write the content to the file called "fname".
borlanic 0:02dd72d1d465 1085 WARNING: if 'fname' names an existing file, it will be
borlanic 0:02dd72d1d465 1086 overwritten!
borlanic 0:02dd72d1d465 1087 """
borlanic 0:02dd72d1d465 1088 return self.config_to_header(self.get_config_data(), fname)