mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
be_bryan 0:b74591d5ab33 1 """Just a template for subclassing"""
be_bryan 0:b74591d5ab33 2 import os
be_bryan 0:b74591d5ab33 3 from abc import abstractmethod, ABCMeta
be_bryan 0:b74591d5ab33 4 import logging
be_bryan 0:b74591d5ab33 5 from os.path import join, dirname, relpath, basename, realpath, normpath
be_bryan 0:b74591d5ab33 6 from itertools import groupby
be_bryan 0:b74591d5ab33 7 from jinja2 import FileSystemLoader, StrictUndefined
be_bryan 0:b74591d5ab33 8 from jinja2.environment import Environment
be_bryan 0:b74591d5ab33 9 import copy
be_bryan 0:b74591d5ab33 10
be_bryan 0:b74591d5ab33 11 from tools.targets import TARGET_MAP
be_bryan 0:b74591d5ab33 12
be_bryan 0:b74591d5ab33 13
be_bryan 0:b74591d5ab33 14 class TargetNotSupportedException(Exception):
be_bryan 0:b74591d5ab33 15 """Indicates that an IDE does not support a particular MCU"""
be_bryan 0:b74591d5ab33 16 pass
be_bryan 0:b74591d5ab33 17
be_bryan 0:b74591d5ab33 18 class ExporterTargetsProperty(object):
be_bryan 0:b74591d5ab33 19 """ Exporter descriptor for TARGETS
be_bryan 0:b74591d5ab33 20 TARGETS as class attribute for backward compatibility
be_bryan 0:b74591d5ab33 21 (allows: if in Exporter.TARGETS)
be_bryan 0:b74591d5ab33 22 """
be_bryan 0:b74591d5ab33 23 def __init__(self, func):
be_bryan 0:b74591d5ab33 24 self.func = func
be_bryan 0:b74591d5ab33 25 def __get__(self, inst, cls):
be_bryan 0:b74591d5ab33 26 return self.func(cls)
be_bryan 0:b74591d5ab33 27
be_bryan 0:b74591d5ab33 28 def deprecated_exporter(CLS):
be_bryan 0:b74591d5ab33 29 old_init = CLS.__init__
be_bryan 0:b74591d5ab33 30 old_name = CLS.NAME
be_bryan 0:b74591d5ab33 31 def __init__(*args, **kwargs):
be_bryan 0:b74591d5ab33 32 print("==================== DEPRECATION NOTICE ====================")
be_bryan 0:b74591d5ab33 33 print("The exporter %s is no longer maintained, and deprecated." % old_name)
be_bryan 0:b74591d5ab33 34 print("%s will be removed from mbed OS for the mbed OS 5.6 release." % old_name)
be_bryan 0:b74591d5ab33 35 old_init(*args, **kwargs)
be_bryan 0:b74591d5ab33 36 CLS.__init__ = __init__
be_bryan 0:b74591d5ab33 37 CLS.NAME = "%s (DEPRECATED)" % old_name
be_bryan 0:b74591d5ab33 38 return CLS
be_bryan 0:b74591d5ab33 39
be_bryan 0:b74591d5ab33 40 class Exporter(object):
be_bryan 0:b74591d5ab33 41 """Exporter base class
be_bryan 0:b74591d5ab33 42
be_bryan 0:b74591d5ab33 43 This class is meant to be extended by individual exporters, and provides a
be_bryan 0:b74591d5ab33 44 few helper methods for implementing an exporter with either jinja2 or
be_bryan 0:b74591d5ab33 45 progen.
be_bryan 0:b74591d5ab33 46 """
be_bryan 0:b74591d5ab33 47 __metaclass__ = ABCMeta
be_bryan 0:b74591d5ab33 48 TEMPLATE_DIR = dirname(__file__)
be_bryan 0:b74591d5ab33 49 DOT_IN_RELATIVE_PATH = False
be_bryan 0:b74591d5ab33 50 NAME = None
be_bryan 0:b74591d5ab33 51 TARGETS = set()
be_bryan 0:b74591d5ab33 52 TOOLCHAIN = None
be_bryan 0:b74591d5ab33 53
be_bryan 0:b74591d5ab33 54
be_bryan 0:b74591d5ab33 55 def __init__(self, target, export_dir, project_name, toolchain,
be_bryan 0:b74591d5ab33 56 extra_symbols=None, resources=None):
be_bryan 0:b74591d5ab33 57 """Initialize an instance of class exporter
be_bryan 0:b74591d5ab33 58 Positional arguments:
be_bryan 0:b74591d5ab33 59 target - the target mcu/board for this project
be_bryan 0:b74591d5ab33 60 export_dir - the directory of the exported project files
be_bryan 0:b74591d5ab33 61 project_name - the name of the project
be_bryan 0:b74591d5ab33 62 toolchain - an instance of class toolchain
be_bryan 0:b74591d5ab33 63
be_bryan 0:b74591d5ab33 64 Keyword arguments:
be_bryan 0:b74591d5ab33 65 extra_symbols - a list of extra macros for the toolchain
be_bryan 0:b74591d5ab33 66 resources - an instance of class Resources
be_bryan 0:b74591d5ab33 67 """
be_bryan 0:b74591d5ab33 68 self.export_dir = export_dir
be_bryan 0:b74591d5ab33 69 self.target = target
be_bryan 0:b74591d5ab33 70 self.project_name = project_name
be_bryan 0:b74591d5ab33 71 self.toolchain = toolchain
be_bryan 0:b74591d5ab33 72 jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
be_bryan 0:b74591d5ab33 73 self.jinja_environment = Environment(loader=jinja_loader)
be_bryan 0:b74591d5ab33 74 self.resources = resources
be_bryan 0:b74591d5ab33 75 self.generated_files = []
be_bryan 0:b74591d5ab33 76 self.static_files = (
be_bryan 0:b74591d5ab33 77 join(self.TEMPLATE_DIR, "GettingStarted.html"),
be_bryan 0:b74591d5ab33 78 join(self.TEMPLATE_DIR, ".mbed"),
be_bryan 0:b74591d5ab33 79 )
be_bryan 0:b74591d5ab33 80 self.builder_files_dict = {}
be_bryan 0:b74591d5ab33 81 self.add_config()
be_bryan 0:b74591d5ab33 82
be_bryan 0:b74591d5ab33 83 def get_toolchain(self):
be_bryan 0:b74591d5ab33 84 """A helper getter function that we should probably eliminate"""
be_bryan 0:b74591d5ab33 85 return self.TOOLCHAIN
be_bryan 0:b74591d5ab33 86
be_bryan 0:b74591d5ab33 87 def add_config(self):
be_bryan 0:b74591d5ab33 88 """Add the containgin directory of mbed_config.h to include dirs"""
be_bryan 0:b74591d5ab33 89 config = self.toolchain.get_config_header()
be_bryan 0:b74591d5ab33 90 if config:
be_bryan 0:b74591d5ab33 91 self.resources.inc_dirs.append(
be_bryan 0:b74591d5ab33 92 dirname(relpath(config,
be_bryan 0:b74591d5ab33 93 self.resources.file_basepath[config])))
be_bryan 0:b74591d5ab33 94
be_bryan 0:b74591d5ab33 95 @property
be_bryan 0:b74591d5ab33 96 def flags(self):
be_bryan 0:b74591d5ab33 97 """Returns a dictionary of toolchain flags.
be_bryan 0:b74591d5ab33 98 Keys of the dictionary are:
be_bryan 0:b74591d5ab33 99 cxx_flags - c++ flags
be_bryan 0:b74591d5ab33 100 c_flags - c flags
be_bryan 0:b74591d5ab33 101 ld_flags - linker flags
be_bryan 0:b74591d5ab33 102 asm_flags - assembler flags
be_bryan 0:b74591d5ab33 103 common_flags - common options
be_bryan 0:b74591d5ab33 104 """
be_bryan 0:b74591d5ab33 105 config_header = self.toolchain.get_config_header()
be_bryan 0:b74591d5ab33 106 flags = {key + "_flags": copy.deepcopy(value) for key, value
be_bryan 0:b74591d5ab33 107 in self.toolchain.flags.iteritems()}
be_bryan 0:b74591d5ab33 108 asm_defines = self.toolchain.get_compile_options(
be_bryan 0:b74591d5ab33 109 self.toolchain.get_symbols(for_asm=True),
be_bryan 0:b74591d5ab33 110 filter(None, self.resources.inc_dirs),
be_bryan 0:b74591d5ab33 111 for_asm=True)
be_bryan 0:b74591d5ab33 112 c_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols()]
be_bryan 0:b74591d5ab33 113 flags['asm_flags'] += asm_defines
be_bryan 0:b74591d5ab33 114 flags['c_flags'] += c_defines
be_bryan 0:b74591d5ab33 115 flags['cxx_flags'] += c_defines
be_bryan 0:b74591d5ab33 116 if config_header:
be_bryan 0:b74591d5ab33 117 config_header = relpath(config_header,
be_bryan 0:b74591d5ab33 118 self.resources.file_basepath[config_header])
be_bryan 0:b74591d5ab33 119 flags['c_flags'] += self.toolchain.get_config_option(config_header)
be_bryan 0:b74591d5ab33 120 flags['cxx_flags'] += self.toolchain.get_config_option(
be_bryan 0:b74591d5ab33 121 config_header)
be_bryan 0:b74591d5ab33 122 return flags
be_bryan 0:b74591d5ab33 123
be_bryan 0:b74591d5ab33 124 def get_source_paths(self):
be_bryan 0:b74591d5ab33 125 """Returns a list of the directories where source files are contained"""
be_bryan 0:b74591d5ab33 126 source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
be_bryan 0:b74591d5ab33 127 'objects', 'libraries']
be_bryan 0:b74591d5ab33 128 source_files = []
be_bryan 0:b74591d5ab33 129 for key in source_keys:
be_bryan 0:b74591d5ab33 130 source_files.extend(getattr(self.resources, key))
be_bryan 0:b74591d5ab33 131 return list(set([os.path.dirname(src) for src in source_files]))
be_bryan 0:b74591d5ab33 132
be_bryan 0:b74591d5ab33 133 def gen_file(self, template_file, data, target_file, **kwargs):
be_bryan 0:b74591d5ab33 134 """Generates a project file from a template using jinja"""
be_bryan 0:b74591d5ab33 135 jinja_loader = FileSystemLoader(
be_bryan 0:b74591d5ab33 136 os.path.dirname(os.path.abspath(__file__)))
be_bryan 0:b74591d5ab33 137 jinja_environment = Environment(loader=jinja_loader,
be_bryan 0:b74591d5ab33 138 undefined=StrictUndefined, **kwargs)
be_bryan 0:b74591d5ab33 139
be_bryan 0:b74591d5ab33 140 template = jinja_environment.get_template(template_file)
be_bryan 0:b74591d5ab33 141 target_text = template.render(data)
be_bryan 0:b74591d5ab33 142
be_bryan 0:b74591d5ab33 143 target_path = join(self.export_dir, target_file)
be_bryan 0:b74591d5ab33 144 logging.debug("Generating: %s", target_path)
be_bryan 0:b74591d5ab33 145 open(target_path, "w").write(target_text)
be_bryan 0:b74591d5ab33 146 self.generated_files += [target_path]
be_bryan 0:b74591d5ab33 147
be_bryan 0:b74591d5ab33 148 def make_key(self, src):
be_bryan 0:b74591d5ab33 149 """From a source file, extract group name
be_bryan 0:b74591d5ab33 150 Positional Arguments:
be_bryan 0:b74591d5ab33 151 src - the src's location
be_bryan 0:b74591d5ab33 152 """
be_bryan 0:b74591d5ab33 153 rel_path = relpath(src, self.resources.file_basepath[src])
be_bryan 0:b74591d5ab33 154 path_list = os.path.normpath(rel_path).split(os.sep)
be_bryan 0:b74591d5ab33 155 assert len(path_list) >= 1
be_bryan 0:b74591d5ab33 156 if len(path_list) == 1:
be_bryan 0:b74591d5ab33 157 key = self.project_name
be_bryan 0:b74591d5ab33 158 else:
be_bryan 0:b74591d5ab33 159 key = path_list[0]
be_bryan 0:b74591d5ab33 160 return key
be_bryan 0:b74591d5ab33 161
be_bryan 0:b74591d5ab33 162 def group_project_files(self, sources):
be_bryan 0:b74591d5ab33 163 """Group the source files by their encompassing directory
be_bryan 0:b74591d5ab33 164 Positional Arguments:
be_bryan 0:b74591d5ab33 165 sources - array of source locations
be_bryan 0:b74591d5ab33 166
be_bryan 0:b74591d5ab33 167 Returns a dictionary of {group name: list of source locations}
be_bryan 0:b74591d5ab33 168 """
be_bryan 0:b74591d5ab33 169 data = sorted(sources, key=self.make_key)
be_bryan 0:b74591d5ab33 170 return {k: list(g) for k,g in groupby(data, self.make_key)}
be_bryan 0:b74591d5ab33 171
be_bryan 0:b74591d5ab33 172 @staticmethod
be_bryan 0:b74591d5ab33 173 def build(project_name, log_name='build_log.txt', cleanup=True):
be_bryan 0:b74591d5ab33 174 """Invoke exporters build command within a subprocess.
be_bryan 0:b74591d5ab33 175 This method is assumed to be executed at the same level as exporter
be_bryan 0:b74591d5ab33 176 project files and project source code.
be_bryan 0:b74591d5ab33 177 See uvision/__init__.py, iar/__init__.py, and makefile/__init__.py for
be_bryan 0:b74591d5ab33 178 example implemenation.
be_bryan 0:b74591d5ab33 179
be_bryan 0:b74591d5ab33 180 Positional Arguments:
be_bryan 0:b74591d5ab33 181 project_name - the name of the project to build; often required by
be_bryan 0:b74591d5ab33 182 exporter's build command.
be_bryan 0:b74591d5ab33 183
be_bryan 0:b74591d5ab33 184 Keyword Args:
be_bryan 0:b74591d5ab33 185 log_name - name of the build log to create. Written and printed out,
be_bryan 0:b74591d5ab33 186 deleted if cleanup = True
be_bryan 0:b74591d5ab33 187 cleanup - a boolean dictating whether exported project files and
be_bryan 0:b74591d5ab33 188 build log are removed after build
be_bryan 0:b74591d5ab33 189
be_bryan 0:b74591d5ab33 190 Returns -1 on failure and 0 on success
be_bryan 0:b74591d5ab33 191 """
be_bryan 0:b74591d5ab33 192 raise NotImplemented("Implement in derived Exporter class.")
be_bryan 0:b74591d5ab33 193
be_bryan 0:b74591d5ab33 194 @abstractmethod
be_bryan 0:b74591d5ab33 195 def generate(self):
be_bryan 0:b74591d5ab33 196 """Generate an IDE/tool specific project file"""
be_bryan 0:b74591d5ab33 197 raise NotImplemented("Implement a generate function in Exporter child class")
be_bryan 0:b74591d5ab33 198
be_bryan 0:b74591d5ab33 199 @classmethod
be_bryan 0:b74591d5ab33 200 def is_target_supported(cls, target_name):
be_bryan 0:b74591d5ab33 201 """Query support for a particular target
be_bryan 0:b74591d5ab33 202
be_bryan 0:b74591d5ab33 203 NOTE: override this method if your exporter does not provide a static list of targets
be_bryan 0:b74591d5ab33 204
be_bryan 0:b74591d5ab33 205 Positional Arguments:
be_bryan 0:b74591d5ab33 206 target_name - the name of the target.
be_bryan 0:b74591d5ab33 207 """
be_bryan 0:b74591d5ab33 208 target = TARGET_MAP[target_name]
be_bryan 0:b74591d5ab33 209 return bool(set(target.resolution_order_names).intersection(set(cls.TARGETS))) \
be_bryan 0:b74591d5ab33 210 and cls.TOOLCHAIN in target.supported_toolchains
be_bryan 0:b74591d5ab33 211
be_bryan 0:b74591d5ab33 212
be_bryan 0:b74591d5ab33 213 @classmethod
be_bryan 0:b74591d5ab33 214 def all_supported_targets(cls):
be_bryan 0:b74591d5ab33 215 return [t for t in TARGET_MAP.keys() if cls.is_target_supported(t)]
be_bryan 0:b74591d5ab33 216
be_bryan 0:b74591d5ab33 217
be_bryan 0:b74591d5ab33 218 def apply_supported_whitelist(compiler, whitelist, target):
be_bryan 0:b74591d5ab33 219 """Generate a list of supported targets for a given compiler and post-binary hook
be_bryan 0:b74591d5ab33 220 white-list."""
be_bryan 0:b74591d5ab33 221 if compiler not in target.supported_toolchains:
be_bryan 0:b74591d5ab33 222 return False
be_bryan 0:b74591d5ab33 223 if not hasattr(target, "post_binary_hook"):
be_bryan 0:b74591d5ab33 224 return True
be_bryan 0:b74591d5ab33 225 if target.post_binary_hook['function'] in whitelist:
be_bryan 0:b74591d5ab33 226 return True
be_bryan 0:b74591d5ab33 227 else:
be_bryan 0:b74591d5ab33 228 return False