Clone of official tools

Committer:
The Other Jimmy
Date:
Thu Jun 22 11:12:28 2017 -0500
Revision:
36:96847d42f010
Child:
43:2a7da56ebd24
Tools release 5.5.1

Who changed what in which revision?

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