Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-sdk-tools by
export/exporters.py@31:182518299918, 2017-01-04 (annotated)
- Committer:
- The Other Jimmy
- Date:
- Wed Jan 04 11:58:24 2017 -0600
- Revision:
- 31:182518299918
- Parent:
- 29:1210849dba19
Update tools to follow mbed-os tools release 5.3.1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
screamer | 0:66f3b5499f7f | 1 | """Just a template for subclassing""" |
The Other Jimmy |
31:182518299918 | 2 | import os |
The Other Jimmy |
31:182518299918 | 3 | from abc import abstractmethod, ABCMeta |
The Other Jimmy |
31:182518299918 | 4 | import logging |
The Other Jimmy |
31:182518299918 | 5 | from os.path import join, dirname, relpath, basename, realpath |
The Other Jimmy |
31:182518299918 | 6 | from itertools import groupby |
The Other Jimmy |
31:182518299918 | 7 | from jinja2 import FileSystemLoader |
screamer | 0:66f3b5499f7f | 8 | from jinja2.environment import Environment |
The Other Jimmy |
31:182518299918 | 9 | import copy |
screamer | 0:66f3b5499f7f | 10 | |
screamer | 0:66f3b5499f7f | 11 | from tools.targets import TARGET_MAP |
screamer | 0:66f3b5499f7f | 12 | |
screamer | 0:66f3b5499f7f | 13 | |
The Other Jimmy |
31:182518299918 | 14 | class TargetNotSupportedException(Exception): |
The Other Jimmy |
31:182518299918 | 15 | """Indicates that an IDE does not support a particular MCU""" |
The Other Jimmy |
31:182518299918 | 16 | pass |
screamer | 13:ab47a20b66f0 | 17 | |
screamer | 24:25bff2709c20 | 18 | class ExporterTargetsProperty(object): |
The Other Jimmy |
31:182518299918 | 19 | """ Exporter descriptor for TARGETS |
The Other Jimmy |
31:182518299918 | 20 | TARGETS as class attribute for backward compatibility |
The Other Jimmy |
31:182518299918 | 21 | (allows: if in Exporter.TARGETS) |
The Other Jimmy |
31:182518299918 | 22 | """ |
screamer | 24:25bff2709c20 | 23 | def __init__(self, func): |
screamer | 24:25bff2709c20 | 24 | self.func = func |
screamer | 24:25bff2709c20 | 25 | def __get__(self, inst, cls): |
screamer | 24:25bff2709c20 | 26 | return self.func(cls) |
screamer | 24:25bff2709c20 | 27 | |
screamer | 0:66f3b5499f7f | 28 | class Exporter(object): |
The Other Jimmy |
31:182518299918 | 29 | """Exporter base class |
The Other Jimmy |
31:182518299918 | 30 | |
The Other Jimmy |
31:182518299918 | 31 | This class is meant to be extended by individual exporters, and provides a |
The Other Jimmy |
31:182518299918 | 32 | few helper methods for implementing an exporter with either jinja2 or |
The Other Jimmy |
31:182518299918 | 33 | progen. |
The Other Jimmy |
31:182518299918 | 34 | """ |
The Other Jimmy |
31:182518299918 | 35 | __metaclass__ = ABCMeta |
screamer | 0:66f3b5499f7f | 36 | TEMPLATE_DIR = dirname(__file__) |
screamer | 0:66f3b5499f7f | 37 | DOT_IN_RELATIVE_PATH = False |
The Other Jimmy |
31:182518299918 | 38 | NAME = None |
The Other Jimmy |
31:182518299918 | 39 | TARGETS = None |
The Other Jimmy |
31:182518299918 | 40 | TOOLCHAIN = None |
screamer | 0:66f3b5499f7f | 41 | |
The Other Jimmy |
31:182518299918 | 42 | |
The Other Jimmy |
31:182518299918 | 43 | def __init__(self, target, export_dir, project_name, toolchain, |
The Other Jimmy |
31:182518299918 | 44 | extra_symbols=None, resources=None): |
The Other Jimmy |
31:182518299918 | 45 | """Initialize an instance of class exporter |
The Other Jimmy |
31:182518299918 | 46 | Positional arguments: |
The Other Jimmy |
31:182518299918 | 47 | target - the target mcu/board for this project |
The Other Jimmy |
31:182518299918 | 48 | export_dir - the directory of the exported project files |
The Other Jimmy |
31:182518299918 | 49 | project_name - the name of the project |
The Other Jimmy |
31:182518299918 | 50 | toolchain - an instance of class toolchain |
The Other Jimmy |
31:182518299918 | 51 | |
The Other Jimmy |
31:182518299918 | 52 | Keyword arguments: |
The Other Jimmy |
31:182518299918 | 53 | extra_symbols - a list of extra macros for the toolchain |
The Other Jimmy |
31:182518299918 | 54 | resources - an instance of class Resources |
The Other Jimmy |
31:182518299918 | 55 | """ |
The Other Jimmy |
31:182518299918 | 56 | self.export_dir = export_dir |
screamer | 0:66f3b5499f7f | 57 | self.target = target |
The Other Jimmy |
31:182518299918 | 58 | self.project_name = project_name |
The Other Jimmy |
31:182518299918 | 59 | self.toolchain = toolchain |
screamer | 0:66f3b5499f7f | 60 | jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__))) |
screamer | 0:66f3b5499f7f | 61 | self.jinja_environment = Environment(loader=jinja_loader) |
The Other Jimmy |
31:182518299918 | 62 | self.resources = resources |
The Other Jimmy |
31:182518299918 | 63 | self.generated_files = [join(self.TEMPLATE_DIR,"GettingStarted.html")] |
The Other Jimmy |
31:182518299918 | 64 | self.builder_files_dict = {} |
The Other Jimmy |
31:182518299918 | 65 | self.add_config() |
screamer | 0:66f3b5499f7f | 66 | |
screamer | 0:66f3b5499f7f | 67 | def get_toolchain(self): |
The Other Jimmy |
31:182518299918 | 68 | """A helper getter function that we should probably eliminate""" |
screamer | 0:66f3b5499f7f | 69 | return self.TOOLCHAIN |
screamer | 0:66f3b5499f7f | 70 | |
The Other Jimmy |
31:182518299918 | 71 | def add_config(self): |
The Other Jimmy |
31:182518299918 | 72 | """Add the containgin directory of mbed_config.h to include dirs""" |
The Other Jimmy |
31:182518299918 | 73 | config = self.toolchain.get_config_header() |
The Other Jimmy |
31:182518299918 | 74 | if config: |
The Other Jimmy |
31:182518299918 | 75 | self.resources.inc_dirs.append( |
The Other Jimmy |
31:182518299918 | 76 | dirname(relpath(config, |
The Other Jimmy |
31:182518299918 | 77 | self.resources.file_basepath[config]))) |
The Other Jimmy |
31:182518299918 | 78 | |
screamer | 13:ab47a20b66f0 | 79 | @property |
screamer | 13:ab47a20b66f0 | 80 | def flags(self): |
The Other Jimmy |
31:182518299918 | 81 | """Returns a dictionary of toolchain flags. |
The Other Jimmy |
31:182518299918 | 82 | Keys of the dictionary are: |
The Other Jimmy |
31:182518299918 | 83 | cxx_flags - c++ flags |
The Other Jimmy |
31:182518299918 | 84 | c_flags - c flags |
The Other Jimmy |
31:182518299918 | 85 | ld_flags - linker flags |
The Other Jimmy |
31:182518299918 | 86 | asm_flags - assembler flags |
The Other Jimmy |
31:182518299918 | 87 | common_flags - common options |
The Other Jimmy |
31:182518299918 | 88 | """ |
The Other Jimmy |
31:182518299918 | 89 | config_header = self.toolchain.get_config_header() |
The Other Jimmy |
31:182518299918 | 90 | flags = {key + "_flags": copy.deepcopy(value) for key, value |
The Other Jimmy |
31:182518299918 | 91 | in self.toolchain.flags.iteritems()} |
The Other Jimmy |
31:182518299918 | 92 | asm_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols(True)] |
The Other Jimmy |
31:182518299918 | 93 | c_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols()] |
The Other Jimmy |
31:182518299918 | 94 | flags['asm_flags'] += asm_defines |
The Other Jimmy |
31:182518299918 | 95 | flags['c_flags'] += c_defines |
The Other Jimmy |
31:182518299918 | 96 | flags['cxx_flags'] += c_defines |
The Other Jimmy |
31:182518299918 | 97 | if config_header: |
The Other Jimmy |
31:182518299918 | 98 | config_header = relpath(config_header, |
The Other Jimmy |
31:182518299918 | 99 | self.resources.file_basepath[config_header]) |
The Other Jimmy |
31:182518299918 | 100 | flags['c_flags'] += self.toolchain.get_config_option(config_header) |
The Other Jimmy |
31:182518299918 | 101 | flags['cxx_flags'] += self.toolchain.get_config_option( |
The Other Jimmy |
31:182518299918 | 102 | config_header) |
The Other Jimmy |
31:182518299918 | 103 | return flags |
The Other Jimmy |
31:182518299918 | 104 | |
The Other Jimmy |
31:182518299918 | 105 | def get_source_paths(self): |
The Other Jimmy |
31:182518299918 | 106 | """Returns a list of the directories where source files are contained""" |
The Other Jimmy |
31:182518299918 | 107 | source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files', |
The Other Jimmy |
31:182518299918 | 108 | 'objects', 'libraries'] |
The Other Jimmy |
31:182518299918 | 109 | source_files = [] |
The Other Jimmy |
31:182518299918 | 110 | for key in source_keys: |
The Other Jimmy |
31:182518299918 | 111 | source_files.extend(getattr(self.resources, key)) |
The Other Jimmy |
31:182518299918 | 112 | return list(set([os.path.dirname(src) for src in source_files])) |
screamer | 13:ab47a20b66f0 | 113 | |
The Other Jimmy |
31:182518299918 | 114 | def gen_file(self, template_file, data, target_file): |
The Other Jimmy |
31:182518299918 | 115 | """Generates a project file from a template using jinja""" |
The Other Jimmy |
31:182518299918 | 116 | jinja_loader = FileSystemLoader( |
The Other Jimmy |
31:182518299918 | 117 | os.path.dirname(os.path.abspath(__file__))) |
The Other Jimmy |
31:182518299918 | 118 | jinja_environment = Environment(loader=jinja_loader) |
The Other Jimmy |
31:182518299918 | 119 | |
The Other Jimmy |
31:182518299918 | 120 | template = jinja_environment.get_template(template_file) |
The Other Jimmy |
31:182518299918 | 121 | target_text = template.render(data) |
The Other Jimmy |
31:182518299918 | 122 | |
The Other Jimmy |
31:182518299918 | 123 | target_path = join(self.export_dir, target_file) |
The Other Jimmy |
31:182518299918 | 124 | logging.debug("Generating: %s", target_path) |
The Other Jimmy |
31:182518299918 | 125 | open(target_path, "w").write(target_text) |
The Other Jimmy |
31:182518299918 | 126 | self.generated_files += [target_path] |
screamer | 13:ab47a20b66f0 | 127 | |
The Other Jimmy |
31:182518299918 | 128 | def make_key(self, src): |
The Other Jimmy |
31:182518299918 | 129 | """From a source file, extract group name |
The Other Jimmy |
31:182518299918 | 130 | Positional Arguments: |
The Other Jimmy |
31:182518299918 | 131 | src - the src's location |
The Other Jimmy |
31:182518299918 | 132 | """ |
The Other Jimmy |
31:182518299918 | 133 | key = basename(dirname(src)) |
The Other Jimmy |
31:182518299918 | 134 | if key == ".": |
The Other Jimmy |
31:182518299918 | 135 | key = basename(realpath(self.export_dir)) |
The Other Jimmy |
31:182518299918 | 136 | return key |
screamer | 0:66f3b5499f7f | 137 | |
The Other Jimmy |
31:182518299918 | 138 | def group_project_files(self, sources): |
The Other Jimmy |
31:182518299918 | 139 | """Group the source files by their encompassing directory |
The Other Jimmy |
31:182518299918 | 140 | Positional Arguments: |
The Other Jimmy |
31:182518299918 | 141 | sources - array of source locations |
The Other Jimmy |
31:182518299918 | 142 | |
The Other Jimmy |
31:182518299918 | 143 | Returns a dictionary of {group name: list of source locations} |
The Other Jimmy |
31:182518299918 | 144 | """ |
The Other Jimmy |
31:182518299918 | 145 | data = sorted(sources, key=self.make_key) |
The Other Jimmy |
31:182518299918 | 146 | return {k: list(g) for k,g in groupby(data, self.make_key)} |
screamer | 0:66f3b5499f7f | 147 | |
screamer | 0:66f3b5499f7f | 148 | @staticmethod |
The Other Jimmy |
31:182518299918 | 149 | def build(project_name, log_name='build_log.txt', cleanup=True): |
The Other Jimmy |
31:182518299918 | 150 | """Invoke exporters build command within a subprocess. |
The Other Jimmy |
31:182518299918 | 151 | This method is assumed to be executed at the same level as exporter |
The Other Jimmy |
31:182518299918 | 152 | project files and project source code. |
The Other Jimmy |
31:182518299918 | 153 | See uvision/__init__.py, iar/__init__.py, and makefile/__init__.py for |
The Other Jimmy |
31:182518299918 | 154 | example implemenation. |
screamer | 0:66f3b5499f7f | 155 | |
The Other Jimmy |
31:182518299918 | 156 | Positional Arguments: |
The Other Jimmy |
31:182518299918 | 157 | project_name - the name of the project to build; often required by |
The Other Jimmy |
31:182518299918 | 158 | exporter's build command. |
screamer | 0:66f3b5499f7f | 159 | |
The Other Jimmy |
31:182518299918 | 160 | Keyword Args: |
The Other Jimmy |
31:182518299918 | 161 | log_name - name of the build log to create. Written and printed out, |
The Other Jimmy |
31:182518299918 | 162 | deleted if cleanup = True |
The Other Jimmy |
31:182518299918 | 163 | cleanup - a boolean dictating whether exported project files and |
The Other Jimmy |
31:182518299918 | 164 | build log are removed after build |
screamer | 0:66f3b5499f7f | 165 | |
The Other Jimmy |
31:182518299918 | 166 | Returns -1 on failure and 0 on success |
screamer | 0:66f3b5499f7f | 167 | """ |
The Other Jimmy |
31:182518299918 | 168 | raise NotImplemented("Implement in derived Exporter class.") |
screamer | 29:1210849dba19 | 169 | |
The Other Jimmy |
31:182518299918 | 170 | @abstractmethod |
The Other Jimmy |
31:182518299918 | 171 | def generate(self): |
The Other Jimmy |
31:182518299918 | 172 | """Generate an IDE/tool specific project file""" |
The Other Jimmy |
31:182518299918 | 173 | raise NotImplemented("Implement a generate function in Exporter child class") |