BA / Mbed OS BaBoRo1
Committer:
borlanic
Date:
Fri Mar 30 14:07:05 2018 +0000
Revision:
4:75df35ef4fb6
Parent:
0:380207fcb5c1
commentar

Who changed what in which revision?

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