Clone of official tools

Committer:
screamer
Date:
Tue Jun 07 11:35:02 2016 +0100
Revision:
8:a8ac6ed29081
Child:
10:2511036308b8
Add missing files and profile support

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 8:a8ac6ed29081 1 """
screamer 8:a8ac6ed29081 2 mbed SDK
screamer 8:a8ac6ed29081 3 Copyright (c) 2016 ARM Limited
screamer 8:a8ac6ed29081 4
screamer 8:a8ac6ed29081 5 Licensed under the Apache License, Version 2.0 (the "License");
screamer 8:a8ac6ed29081 6 you may not use this file except in compliance with the License.
screamer 8:a8ac6ed29081 7 You may obtain a copy of the License at
screamer 8:a8ac6ed29081 8
screamer 8:a8ac6ed29081 9 http://www.apache.org/licenses/LICENSE-2.0
screamer 8:a8ac6ed29081 10
screamer 8:a8ac6ed29081 11 Unless required by applicable law or agreed to in writing, software
screamer 8:a8ac6ed29081 12 distributed under the License is distributed on an "AS IS" BASIS,
screamer 8:a8ac6ed29081 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 8:a8ac6ed29081 14 See the License for the specific language governing permissions and
screamer 8:a8ac6ed29081 15 limitations under the License.
screamer 8:a8ac6ed29081 16 """
screamer 8:a8ac6ed29081 17
screamer 8:a8ac6ed29081 18 # Implementation of mbed configuration mechanism
screamer 8:a8ac6ed29081 19 from copy import deepcopy
screamer 8:a8ac6ed29081 20 from collections import OrderedDict
screamer 8:a8ac6ed29081 21 from tools.utils import json_file_to_dict, ToolException
screamer 8:a8ac6ed29081 22 from tools.targets import Target
screamer 8:a8ac6ed29081 23 import os
screamer 8:a8ac6ed29081 24
screamer 8:a8ac6ed29081 25 # Base class for all configuration exceptions
screamer 8:a8ac6ed29081 26 class ConfigException(Exception):
screamer 8:a8ac6ed29081 27 pass
screamer 8:a8ac6ed29081 28
screamer 8:a8ac6ed29081 29 # This class keeps information about a single configuration parameter
screamer 8:a8ac6ed29081 30 class ConfigParameter:
screamer 8:a8ac6ed29081 31 # name: the name of the configuration parameter
screamer 8:a8ac6ed29081 32 # data: the data associated with the configuration parameter
screamer 8:a8ac6ed29081 33 # unit_name: the unit (target/library/application) that defines this parameter
screamer 8:a8ac6ed29081 34 # unit_ kind: the kind of the unit ("target", "library" or "application")
screamer 8:a8ac6ed29081 35 def __init__(self, name, data, unit_name, unit_kind):
screamer 8:a8ac6ed29081 36 self.name = self.get_full_name(name, unit_name, unit_kind, allow_prefix = False)
screamer 8:a8ac6ed29081 37 self.defined_by = self.get_display_name(unit_name, unit_kind)
screamer 8:a8ac6ed29081 38 self.set_by = self.defined_by
screamer 8:a8ac6ed29081 39 self.help_text = data.get("help", None)
screamer 8:a8ac6ed29081 40 self.value = data.get("value", None)
screamer 8:a8ac6ed29081 41 self.required = data.get("required", False)
screamer 8:a8ac6ed29081 42 self.macro_name = data.get("macro_name", "MBED_CONF_%s" % self.sanitize(self.name.upper()))
screamer 8:a8ac6ed29081 43
screamer 8:a8ac6ed29081 44 # Return the full (prefixed) name of a parameter.
screamer 8:a8ac6ed29081 45 # If the parameter already has a prefix, check if it is valid
screamer 8:a8ac6ed29081 46 # name: the simple (unqualified) name of the parameter
screamer 8:a8ac6ed29081 47 # unit_name: the unit (target/library/application) that defines this parameter
screamer 8:a8ac6ed29081 48 # unit_kind: the kind of the unit ("target", "library" or "application")
screamer 8:a8ac6ed29081 49 # label: the name of the label in the 'target_config_overrides' section (optional)
screamer 8:a8ac6ed29081 50 # allow_prefix: True to allo the original name to have a prefix, False otherwise
screamer 8:a8ac6ed29081 51 @staticmethod
screamer 8:a8ac6ed29081 52 def get_full_name(name, unit_name, unit_kind, label = None, allow_prefix = True):
screamer 8:a8ac6ed29081 53 if name.find('.') == -1: # the name is not prefixed
screamer 8:a8ac6ed29081 54 if unit_kind == "target":
screamer 8:a8ac6ed29081 55 prefix = "target."
screamer 8:a8ac6ed29081 56 elif unit_kind == "application":
screamer 8:a8ac6ed29081 57 prefix = "app."
screamer 8:a8ac6ed29081 58 else:
screamer 8:a8ac6ed29081 59 prefix = unit_name + '.'
screamer 8:a8ac6ed29081 60 return prefix + name
screamer 8:a8ac6ed29081 61 # The name has a prefix, so check if it is valid
screamer 8:a8ac6ed29081 62 if not allow_prefix:
screamer 8:a8ac6ed29081 63 raise ConfigException("Invalid parameter name '%s' in '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 64 temp = name.split(".")
screamer 8:a8ac6ed29081 65 # Check if the parameter syntax is correct (must be unit_name.parameter_name)
screamer 8:a8ac6ed29081 66 if len(temp) != 2:
screamer 8:a8ac6ed29081 67 raise ConfigException("Invalid parameter name '%s' in '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 68 prefix = temp[0]
screamer 8:a8ac6ed29081 69 # Check if the given parameter prefix matches the expected prefix
screamer 8:a8ac6ed29081 70 if (unit_kind == "library" and prefix != unit_name) or (unit_kind == "target" and prefix != "target"):
screamer 8:a8ac6ed29081 71 raise ConfigException("Invalid prefix '%s' for parameter name '%s' in '%s'" % (prefix, name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 72 return name
screamer 8:a8ac6ed29081 73
screamer 8:a8ac6ed29081 74 # Return the name displayed for a unit when interogating the origin
screamer 8:a8ac6ed29081 75 # and the last set place of a parameter
screamer 8:a8ac6ed29081 76 # unit_name: the unit (target/library/application) that defines this parameter
screamer 8:a8ac6ed29081 77 # unit_kind: the kind of the unit ("target", "library" or "application")
screamer 8:a8ac6ed29081 78 # label: the name of the label in the 'target_config_overrides' section (optional)
screamer 8:a8ac6ed29081 79 @staticmethod
screamer 8:a8ac6ed29081 80 def get_display_name(unit_name, unit_kind, label = None):
screamer 8:a8ac6ed29081 81 if unit_kind == "target":
screamer 8:a8ac6ed29081 82 return "target:" + unit_name
screamer 8:a8ac6ed29081 83 elif unit_kind == "application":
screamer 8:a8ac6ed29081 84 return "application%s" % ("[%s]" % label if label else "")
screamer 8:a8ac6ed29081 85 else: # library
screamer 8:a8ac6ed29081 86 return "library:%s%s" % (unit_name, "[%s]" % label if label else "")
screamer 8:a8ac6ed29081 87
screamer 8:a8ac6ed29081 88 # "Sanitize" a name so that it is a valid C macro name
screamer 8:a8ac6ed29081 89 # Currently it simply replaces '.' and '-' with '_'
screamer 8:a8ac6ed29081 90 # name: the un-sanitized name.
screamer 8:a8ac6ed29081 91 @staticmethod
screamer 8:a8ac6ed29081 92 def sanitize(name):
screamer 8:a8ac6ed29081 93 return name.replace('.', '_').replace('-', '_')
screamer 8:a8ac6ed29081 94
screamer 8:a8ac6ed29081 95 # Sets a value for this parameter, remember the place where it was set
screamer 8:a8ac6ed29081 96 # value: the value of the parameter
screamer 8:a8ac6ed29081 97 # unit_name: the unit (target/library/application) that defines this parameter
screamer 8:a8ac6ed29081 98 # unit_ kind: the kind of the unit ("target", "library" or "application")
screamer 8:a8ac6ed29081 99 # label: the name of the label in the 'target_config_overrides' section (optional)
screamer 8:a8ac6ed29081 100 def set_value(self, value, unit_name, unit_kind, label = None):
screamer 8:a8ac6ed29081 101 self.value = value
screamer 8:a8ac6ed29081 102 self.set_by = self.get_display_name(unit_name, unit_kind, label)
screamer 8:a8ac6ed29081 103
screamer 8:a8ac6ed29081 104 # Return the string representation of this configuration parameter
screamer 8:a8ac6ed29081 105 def __str__(self):
screamer 8:a8ac6ed29081 106 if self.value is not None:
screamer 8:a8ac6ed29081 107 return '%s = %s (macro name: "%s")' % (self.name, self.value, self.macro_name)
screamer 8:a8ac6ed29081 108 else:
screamer 8:a8ac6ed29081 109 return '%s has no value' % self.name
screamer 8:a8ac6ed29081 110
screamer 8:a8ac6ed29081 111 # Return a verbose description of this configuration paramater as a string
screamer 8:a8ac6ed29081 112 def get_verbose_description(self):
screamer 8:a8ac6ed29081 113 desc = "Name: %s%s\n" % (self.name, " (required parameter)" if self.required else "")
screamer 8:a8ac6ed29081 114 if self.help_text:
screamer 8:a8ac6ed29081 115 desc += " Description: %s\n" % self.help_text
screamer 8:a8ac6ed29081 116 desc += " Defined by: %s\n" % self.defined_by
screamer 8:a8ac6ed29081 117 if not self.value:
screamer 8:a8ac6ed29081 118 return desc + " No value set"
screamer 8:a8ac6ed29081 119 desc += " Macro name: %s\n" % self.macro_name
screamer 8:a8ac6ed29081 120 desc += " Value: %s (set by %s)" % (self.value, self.set_by)
screamer 8:a8ac6ed29081 121 return desc
screamer 8:a8ac6ed29081 122
screamer 8:a8ac6ed29081 123 # A representation of a configuration macro. It handles both macros without a value (MACRO)
screamer 8:a8ac6ed29081 124 # and with a value (MACRO=VALUE)
screamer 8:a8ac6ed29081 125 class ConfigMacro:
screamer 8:a8ac6ed29081 126 def __init__(self, name, unit_name, unit_kind):
screamer 8:a8ac6ed29081 127 self.name = name
screamer 8:a8ac6ed29081 128 self.defined_by = ConfigParameter.get_display_name(unit_name, unit_kind)
screamer 8:a8ac6ed29081 129 if name.find("=") != -1:
screamer 8:a8ac6ed29081 130 tmp = name.split("=")
screamer 8:a8ac6ed29081 131 if len(tmp) != 2:
screamer 8:a8ac6ed29081 132 raise ValueError("Invalid macro definition '%s' in '%s'" % (name, self.defined_by))
screamer 8:a8ac6ed29081 133 self.macro_name = tmp[0]
screamer 8:a8ac6ed29081 134 else:
screamer 8:a8ac6ed29081 135 self.macro_name = name
screamer 8:a8ac6ed29081 136
screamer 8:a8ac6ed29081 137 # 'Config' implements the mbed configuration mechanism
screamer 8:a8ac6ed29081 138 class Config:
screamer 8:a8ac6ed29081 139 # Libraries and applications have different names for their configuration files
screamer 8:a8ac6ed29081 140 __mbed_app_config_name = "mbed_app.json"
screamer 8:a8ac6ed29081 141 __mbed_lib_config_name = "mbed_lib.json"
screamer 8:a8ac6ed29081 142
screamer 8:a8ac6ed29081 143 # Allowed keys in configuration dictionaries
screamer 8:a8ac6ed29081 144 # (targets can have any kind of keys, so this validation is not applicable to them)
screamer 8:a8ac6ed29081 145 __allowed_keys = {
screamer 8:a8ac6ed29081 146 "library": set(["name", "config", "target_overrides", "macros", "__config_path"]),
screamer 8:a8ac6ed29081 147 "application": set(["config", "custom_targets", "target_overrides", "macros", "__config_path"])
screamer 8:a8ac6ed29081 148 }
screamer 8:a8ac6ed29081 149
screamer 8:a8ac6ed29081 150 # The initialization arguments for Config are:
screamer 8:a8ac6ed29081 151 # target: the name of the mbed target used for this configuration instance
screamer 8:a8ac6ed29081 152 # top_level_dirs: a list of top level source directories (where mbed_abb_config.json could be found)
screamer 8:a8ac6ed29081 153 # __init__ will look for the application configuration file in top_level_dirs.
screamer 8:a8ac6ed29081 154 # If found once, it'll parse it and check if it has a custom_targets function.
screamer 8:a8ac6ed29081 155 # If it does, it'll update the list of targets if need.
screamer 8:a8ac6ed29081 156 # If found more than once, an exception is raised
screamer 8:a8ac6ed29081 157 # top_level_dirs can be None (in this case, mbed_app_config.json will not be searched)
screamer 8:a8ac6ed29081 158 def __init__(self, target, top_level_dirs = []):
screamer 8:a8ac6ed29081 159 app_config_location = None
screamer 8:a8ac6ed29081 160 for s in (top_level_dirs or []):
screamer 8:a8ac6ed29081 161 full_path = os.path.join(s, self.__mbed_app_config_name)
screamer 8:a8ac6ed29081 162 if os.path.isfile(full_path):
screamer 8:a8ac6ed29081 163 if app_config_location is not None:
screamer 8:a8ac6ed29081 164 raise ConfigException("Duplicate '%s' file in '%s' and '%s'" % (self.__mbed_app_config_name, app_config_location, full_path))
screamer 8:a8ac6ed29081 165 else:
screamer 8:a8ac6ed29081 166 app_config_location = full_path
screamer 8:a8ac6ed29081 167 self.app_config_data = json_file_to_dict(app_config_location) if app_config_location else {}
screamer 8:a8ac6ed29081 168 # Check the keys in the application configuration data
screamer 8:a8ac6ed29081 169 unknown_keys = set(self.app_config_data.keys()) - self.__allowed_keys["application"]
screamer 8:a8ac6ed29081 170 if unknown_keys:
screamer 8:a8ac6ed29081 171 raise ConfigException("Unknown key(s) '%s' in %s" % (",".join(unknown_keys), self.__mbed_app_config_name))
screamer 8:a8ac6ed29081 172 # Update the list of targets with the ones defined in the application config, if applicable
screamer 8:a8ac6ed29081 173 Target.add_py_targets(self.app_config_data.get("custom_targets", {}))
screamer 8:a8ac6ed29081 174 self.lib_config_data = {}
screamer 8:a8ac6ed29081 175 # Make sure that each config is processed only once
screamer 8:a8ac6ed29081 176 self.processed_configs = {}
screamer 8:a8ac6ed29081 177 self.target = target if isinstance(target, str) else target.name
screamer 8:a8ac6ed29081 178 self.target_labels = Target.get_target(self.target).get_labels()
screamer 8:a8ac6ed29081 179
screamer 8:a8ac6ed29081 180 # Add one or more configuration files
screamer 8:a8ac6ed29081 181 def add_config_files(self, flist):
screamer 8:a8ac6ed29081 182 for f in flist:
screamer 8:a8ac6ed29081 183 if not f.endswith(self.__mbed_lib_config_name):
screamer 8:a8ac6ed29081 184 continue
screamer 8:a8ac6ed29081 185 full_path = os.path.normpath(os.path.abspath(f))
screamer 8:a8ac6ed29081 186 # Check that we didn't already process this file
screamer 8:a8ac6ed29081 187 if self.processed_configs.has_key(full_path):
screamer 8:a8ac6ed29081 188 continue
screamer 8:a8ac6ed29081 189 self.processed_configs[full_path] = True
screamer 8:a8ac6ed29081 190 # Read the library configuration and add a "__full_config_path" attribute to it
screamer 8:a8ac6ed29081 191 cfg = json_file_to_dict(f)
screamer 8:a8ac6ed29081 192 cfg["__config_path"] = full_path
screamer 8:a8ac6ed29081 193 # If there's already a configuration for a module with the same name, exit with error
screamer 8:a8ac6ed29081 194 if self.lib_config_data.has_key(cfg["name"]):
screamer 8:a8ac6ed29081 195 raise ConfigException("Library name '%s' is not unique (defined in '%s' and '%s')" % (cfg["name"], full_path, self.lib_config_data[cfg["name"]]["__config_path"]))
screamer 8:a8ac6ed29081 196 self.lib_config_data[cfg["name"]] = cfg
screamer 8:a8ac6ed29081 197
screamer 8:a8ac6ed29081 198 # Helper function: process a "config_parameters" section in either a target, a library or the application
screamer 8:a8ac6ed29081 199 # data: a dictionary with the configuration parameters
screamer 8:a8ac6ed29081 200 # params: storage for the discovered configuration parameters
screamer 8:a8ac6ed29081 201 # unit_name: the unit (target/library/application) that defines this parameter
screamer 8:a8ac6ed29081 202 # unit_kind: the kind of the unit ("target", "library" or "application")
screamer 8:a8ac6ed29081 203 def _process_config_parameters(self, data, params, unit_name, unit_kind):
screamer 8:a8ac6ed29081 204 for name, v in data.items():
screamer 8:a8ac6ed29081 205 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind)
screamer 8:a8ac6ed29081 206 # If the parameter was already defined, raise an error
screamer 8:a8ac6ed29081 207 if full_name in params:
screamer 8:a8ac6ed29081 208 raise ConfigException("Parameter name '%s' defined in both '%s' and '%s'" % (name, ConfigParameter.get_display_name(unit_name, unit_kind), params[full_name].defined_by))
screamer 8:a8ac6ed29081 209 # Otherwise add it to the list of known parameters
screamer 8:a8ac6ed29081 210 # If "v" is not a dictionary, this is a shortcut definition, otherwise it is a full definition
screamer 8:a8ac6ed29081 211 params[full_name] = ConfigParameter(name, v if isinstance(v, dict) else {"value": v}, unit_name, unit_kind)
screamer 8:a8ac6ed29081 212 return params
screamer 8:a8ac6ed29081 213
screamer 8:a8ac6ed29081 214 # Helper function: process "config_parameters" and "target_config_overrides" in a given dictionary
screamer 8:a8ac6ed29081 215 # data: the configuration data of the library/appliation
screamer 8:a8ac6ed29081 216 # params: storage for the discovered configuration parameters
screamer 8:a8ac6ed29081 217 # unit_name: the unit (library/application) that defines this parameter
screamer 8:a8ac6ed29081 218 # unit_kind: the kind of the unit ("library" or "application")
screamer 8:a8ac6ed29081 219 def _process_config_and_overrides(self, data, params, unit_name, unit_kind):
screamer 8:a8ac6ed29081 220 self._process_config_parameters(data.get("config", {}), params, unit_name, unit_kind)
screamer 8:a8ac6ed29081 221 for label, overrides in data.get("target_overrides", {}).items():
screamer 8:a8ac6ed29081 222 # If the label is defined by the target or it has the special value "*", process the overrides
screamer 8:a8ac6ed29081 223 if (label == '*') or (label in self.target_labels):
screamer 8:a8ac6ed29081 224 for name, v in overrides.items():
screamer 8:a8ac6ed29081 225 # Get the full name of the parameter
screamer 8:a8ac6ed29081 226 full_name = ConfigParameter.get_full_name(name, unit_name, unit_kind, label)
screamer 8:a8ac6ed29081 227 # If an attempt is made to override a parameter that isn't defined, raise an error
screamer 8:a8ac6ed29081 228 if not full_name in params:
screamer 8:a8ac6ed29081 229 raise ConfigException("Attempt to override undefined parameter '%s' in '%s'" % (full_name, ConfigParameter.get_display_name(unit_name, unit_kind, label)))
screamer 8:a8ac6ed29081 230 params[full_name].set_value(v, unit_name, unit_kind, label)
screamer 8:a8ac6ed29081 231 return params
screamer 8:a8ac6ed29081 232
screamer 8:a8ac6ed29081 233 # Read and interpret configuration data defined by targets
screamer 8:a8ac6ed29081 234 def get_target_config_data(self):
screamer 8:a8ac6ed29081 235 # We consider the resolution order for our target and sort it by level reversed,
screamer 8:a8ac6ed29081 236 # so that we first look at the top level target (the parent), then its direct children,
screamer 8:a8ac6ed29081 237 # then the children's children and so on, until we reach self.target
screamer 8:a8ac6ed29081 238 # TODO: this might not work so well in some multiple inheritance scenarios
screamer 8:a8ac6ed29081 239 # At each step, look at two keys of the target data:
screamer 8:a8ac6ed29081 240 # - config_parameters: used to define new configuration parameters
screamer 8:a8ac6ed29081 241 # - config_overrides: used to override already defined configuration parameters
screamer 8:a8ac6ed29081 242 params, json_data = {}, Target.get_json_target_data()
screamer 8:a8ac6ed29081 243 resolution_order = [e[0] for e in sorted(Target.get_target(self.target).resolution_order, key = lambda e: e[1], reverse = True)]
screamer 8:a8ac6ed29081 244 for tname in resolution_order:
screamer 8:a8ac6ed29081 245 # Read the target data directly from its description
screamer 8:a8ac6ed29081 246 t = json_data[tname]
screamer 8:a8ac6ed29081 247 # Process definitions first
screamer 8:a8ac6ed29081 248 self._process_config_parameters(t.get("config", {}), params, tname, "target")
screamer 8:a8ac6ed29081 249 # Then process overrides
screamer 8:a8ac6ed29081 250 for name, v in t.get("overrides", {}).items():
screamer 8:a8ac6ed29081 251 full_name = ConfigParameter.get_full_name(name, tname, "target")
screamer 8:a8ac6ed29081 252 # If the parameter name is not defined or if there isn't a path from this target to the target where the
screamer 8:a8ac6ed29081 253 # parameter was defined in the target inheritance tree, raise an error
screamer 8:a8ac6ed29081 254 # We need to use 'defined_by[7:]' to remove the "target:" prefix from defined_by
screamer 8:a8ac6ed29081 255 if (not full_name in params) or (not params[full_name].defined_by[7:] in Target.get_target(tname).resolution_order_names):
screamer 8:a8ac6ed29081 256 raise ConfigException("Attempt to override undefined parameter '%s' in '%s'" % (name, ConfigParameter.get_display_name(tname, "target")))
screamer 8:a8ac6ed29081 257 # Otherwise update the value of the parameter
screamer 8:a8ac6ed29081 258 params[full_name].set_value(v, tname, "target")
screamer 8:a8ac6ed29081 259 return params
screamer 8:a8ac6ed29081 260
screamer 8:a8ac6ed29081 261 # Helper function: process a macro definition, checking for incompatible duplicate definitions
screamer 8:a8ac6ed29081 262 # mlist: list of macro names to process
screamer 8:a8ac6ed29081 263 # macros: dictionary with currently discovered macros
screamer 8:a8ac6ed29081 264 # unit_name: the unit (library/application) that defines this macro
screamer 8:a8ac6ed29081 265 # unit_kind: the kind of the unit ("library" or "application")
screamer 8:a8ac6ed29081 266 def _process_macros(self, mlist, macros, unit_name, unit_kind):
screamer 8:a8ac6ed29081 267 for mname in mlist:
screamer 8:a8ac6ed29081 268 m = ConfigMacro(mname, unit_name, unit_kind)
screamer 8:a8ac6ed29081 269 if (m.macro_name in macros) and (macros[m.macro_name].name != mname):
screamer 8:a8ac6ed29081 270 # Found an incompatible definition of the macro in another module, so raise an error
screamer 8:a8ac6ed29081 271 full_unit_name = ConfigParameter.get_display_name(unit_name, unit_kind)
screamer 8:a8ac6ed29081 272 raise ConfigException("Macro '%s' defined in both '%s' and '%s' with incompatible values" % (m.macro_name, macros[m.macro_name].defined_by, full_unit_name))
screamer 8:a8ac6ed29081 273 macros[m.macro_name] = m
screamer 8:a8ac6ed29081 274
screamer 8:a8ac6ed29081 275 # Read and interpret configuration data defined by libs
screamer 8:a8ac6ed29081 276 # It is assumed that "add_config_files" above was already called and the library configuration data
screamer 8:a8ac6ed29081 277 # exists in self.lib_config_data
screamer 8:a8ac6ed29081 278 def get_lib_config_data(self):
screamer 8:a8ac6ed29081 279 all_params, macros = {}, {}
screamer 8:a8ac6ed29081 280 for lib_name, lib_data in self.lib_config_data.items():
screamer 8:a8ac6ed29081 281 unknown_keys = set(lib_data.keys()) - self.__allowed_keys["library"]
screamer 8:a8ac6ed29081 282 if unknown_keys:
screamer 8:a8ac6ed29081 283 raise ConfigException("Unknown key(s) '%s' in %s" % (",".join(unknown_keys), lib_name))
screamer 8:a8ac6ed29081 284 all_params.update(self._process_config_and_overrides(lib_data, {}, lib_name, "library"))
screamer 8:a8ac6ed29081 285 self._process_macros(lib_data.get("macros", []), macros, lib_name, "library")
screamer 8:a8ac6ed29081 286 return all_params, macros
screamer 8:a8ac6ed29081 287
screamer 8:a8ac6ed29081 288 # Read and interpret the configuration data defined by the target
screamer 8:a8ac6ed29081 289 # The target can override any configuration parameter, as well as define its own configuration data
screamer 8:a8ac6ed29081 290 # params: the dictionary with configuration parameters found so far (in the target and in libraries)
screamer 8:a8ac6ed29081 291 # macros: the list of macros defined in the configuration
screamer 8:a8ac6ed29081 292 def get_app_config_data(self, params, macros):
screamer 8:a8ac6ed29081 293 app_cfg = self.app_config_data
screamer 8:a8ac6ed29081 294 # The application can have a "config_parameters" and a "target_config_overrides" section just like a library
screamer 8:a8ac6ed29081 295 self._process_config_and_overrides(app_cfg, params, "app", "application")
screamer 8:a8ac6ed29081 296 # The application can also defined macros
screamer 8:a8ac6ed29081 297 self._process_macros(app_cfg.get("macros", []), macros, "app", "application")
screamer 8:a8ac6ed29081 298
screamer 8:a8ac6ed29081 299 # Return the configuration data in two parts:
screamer 8:a8ac6ed29081 300 # - params: a dictionary with (name, ConfigParam) entries
screamer 8:a8ac6ed29081 301 # - macros: the list of macros defined with "macros" in libraries and in the application
screamer 8:a8ac6ed29081 302 def get_config_data(self):
screamer 8:a8ac6ed29081 303 all_params = self.get_target_config_data()
screamer 8:a8ac6ed29081 304 lib_params, macros = self.get_lib_config_data()
screamer 8:a8ac6ed29081 305 all_params.update(lib_params)
screamer 8:a8ac6ed29081 306 self.get_app_config_data(all_params, macros)
screamer 8:a8ac6ed29081 307 return all_params, [m.name for m in macros.values()]
screamer 8:a8ac6ed29081 308
screamer 8:a8ac6ed29081 309 # Helper: verify if there are any required parameters without a value in 'params'
screamer 8:a8ac6ed29081 310 def _check_required_parameters(self, params):
screamer 8:a8ac6ed29081 311 for p in params.values():
screamer 8:a8ac6ed29081 312 if p.required and (p.value is None):
screamer 8:a8ac6ed29081 313 raise ConfigException("Required parameter '%s' defined by '%s' doesn't have a value" % (p.name, p.defined_by))
screamer 8:a8ac6ed29081 314
screamer 8:a8ac6ed29081 315 # Return the macro definitions generated for a dictionary of configuration parameters
screamer 8:a8ac6ed29081 316 # params: a dictionary of (name, ConfigParameters instance) mappings
screamer 8:a8ac6ed29081 317 @staticmethod
screamer 8:a8ac6ed29081 318 def parameters_to_macros(params):
screamer 8:a8ac6ed29081 319 return ['%s=%s' % (m.macro_name, m.value) for m in params.values() if m.value is not None]
screamer 8:a8ac6ed29081 320
screamer 8:a8ac6ed29081 321 # Return the configuration data converted to a list of C macros
screamer 8:a8ac6ed29081 322 def get_config_data_macros(self):
screamer 8:a8ac6ed29081 323 params, macros = self.get_config_data()
screamer 8:a8ac6ed29081 324 self._check_required_parameters(params)
screamer 8:a8ac6ed29081 325 return macros + self.parameters_to_macros(params)