Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

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