Committer:
nexpaq
Date:
Fri Nov 04 20:54:50 2016 +0000
Revision:
1:d96dbedaebdb
Parent:
0:6c56fb4bc5f0
Removed extra directories for other platforms

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nexpaq 0:6c56fb4bc5f0 1 """Just a template for subclassing"""
nexpaq 0:6c56fb4bc5f0 2 import os
nexpaq 0:6c56fb4bc5f0 3 import sys
nexpaq 0:6c56fb4bc5f0 4 import logging
nexpaq 0:6c56fb4bc5f0 5 from os.path import join, dirname, relpath
nexpaq 0:6c56fb4bc5f0 6 from itertools import groupby
nexpaq 0:6c56fb4bc5f0 7 from jinja2 import FileSystemLoader
nexpaq 0:6c56fb4bc5f0 8 from jinja2.environment import Environment
nexpaq 0:6c56fb4bc5f0 9
nexpaq 0:6c56fb4bc5f0 10 from tools.targets import TARGET_MAP
nexpaq 0:6c56fb4bc5f0 11 from project_generator.tools import tool
nexpaq 0:6c56fb4bc5f0 12 from project_generator.tools_supported import ToolsSupported
nexpaq 0:6c56fb4bc5f0 13 from project_generator.settings import ProjectSettings
nexpaq 0:6c56fb4bc5f0 14 from project_generator_definitions.definitions import ProGenDef
nexpaq 0:6c56fb4bc5f0 15
nexpaq 0:6c56fb4bc5f0 16
nexpaq 0:6c56fb4bc5f0 17 class OldLibrariesException(Exception):
nexpaq 0:6c56fb4bc5f0 18 """Exception that indicates an export can not complete due to an out of date
nexpaq 0:6c56fb4bc5f0 19 library version.
nexpaq 0:6c56fb4bc5f0 20 """
nexpaq 0:6c56fb4bc5f0 21 pass
nexpaq 0:6c56fb4bc5f0 22
nexpaq 0:6c56fb4bc5f0 23 class FailedBuildException(Exception):
nexpaq 0:6c56fb4bc5f0 24 """Exception that indicates that a build failed"""
nexpaq 0:6c56fb4bc5f0 25 pass
nexpaq 0:6c56fb4bc5f0 26
nexpaq 0:6c56fb4bc5f0 27 class TargetNotSupportedException(Exception):
nexpaq 0:6c56fb4bc5f0 28 """Indicates that an IDE does not support a particular MCU"""
nexpaq 0:6c56fb4bc5f0 29 pass
nexpaq 0:6c56fb4bc5f0 30
nexpaq 0:6c56fb4bc5f0 31 class ExporterTargetsProperty(object):
nexpaq 0:6c56fb4bc5f0 32 """ Exporter descriptor for TARGETS
nexpaq 0:6c56fb4bc5f0 33 TARGETS as class attribute for backward compatibility
nexpaq 0:6c56fb4bc5f0 34 (allows: if in Exporter.TARGETS)
nexpaq 0:6c56fb4bc5f0 35 """
nexpaq 0:6c56fb4bc5f0 36 def __init__(self, func):
nexpaq 0:6c56fb4bc5f0 37 self.func = func
nexpaq 0:6c56fb4bc5f0 38 def __get__(self, inst, cls):
nexpaq 0:6c56fb4bc5f0 39 return self.func(cls)
nexpaq 0:6c56fb4bc5f0 40
nexpaq 0:6c56fb4bc5f0 41 class Exporter(object):
nexpaq 0:6c56fb4bc5f0 42 """Exporter base class
nexpaq 0:6c56fb4bc5f0 43
nexpaq 0:6c56fb4bc5f0 44 This class is meant to be extended by individual exporters, and provides a
nexpaq 0:6c56fb4bc5f0 45 few helper methods for implementing an exporter with either jinja2 or
nexpaq 0:6c56fb4bc5f0 46 progen.
nexpaq 0:6c56fb4bc5f0 47 """
nexpaq 0:6c56fb4bc5f0 48 TEMPLATE_DIR = dirname(__file__)
nexpaq 0:6c56fb4bc5f0 49 DOT_IN_RELATIVE_PATH = False
nexpaq 0:6c56fb4bc5f0 50 NAME = None
nexpaq 0:6c56fb4bc5f0 51 TARGETS = None
nexpaq 0:6c56fb4bc5f0 52 TOOLCHAIN = None
nexpaq 0:6c56fb4bc5f0 53
nexpaq 0:6c56fb4bc5f0 54 def __init__(self, target, export_dir, project_name, toolchain,
nexpaq 0:6c56fb4bc5f0 55 extra_symbols=None, resources=None):
nexpaq 0:6c56fb4bc5f0 56 """Initialize an instance of class exporter
nexpaq 0:6c56fb4bc5f0 57 Positional arguments:
nexpaq 0:6c56fb4bc5f0 58 target - the target mcu/board for this project
nexpaq 0:6c56fb4bc5f0 59 export_dir - the directory of the exported project files
nexpaq 0:6c56fb4bc5f0 60 project_name - the name of the project
nexpaq 0:6c56fb4bc5f0 61 toolchain - an instance of class toolchain
nexpaq 0:6c56fb4bc5f0 62
nexpaq 0:6c56fb4bc5f0 63 Keyword arguments:
nexpaq 0:6c56fb4bc5f0 64 extra_symbols - a list of extra macros for the toolchain
nexpaq 0:6c56fb4bc5f0 65 resources - an instance of class Resources
nexpaq 0:6c56fb4bc5f0 66 """
nexpaq 0:6c56fb4bc5f0 67 self.export_dir = export_dir
nexpaq 0:6c56fb4bc5f0 68 self.target = target
nexpaq 0:6c56fb4bc5f0 69 self.project_name = project_name
nexpaq 0:6c56fb4bc5f0 70 self.toolchain = toolchain
nexpaq 0:6c56fb4bc5f0 71 jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
nexpaq 0:6c56fb4bc5f0 72 self.jinja_environment = Environment(loader=jinja_loader)
nexpaq 0:6c56fb4bc5f0 73 self.resources = resources
nexpaq 0:6c56fb4bc5f0 74 self.generated_files = []
nexpaq 0:6c56fb4bc5f0 75 self.builder_files_dict = {}
nexpaq 0:6c56fb4bc5f0 76
nexpaq 0:6c56fb4bc5f0 77 def get_toolchain(self):
nexpaq 0:6c56fb4bc5f0 78 """A helper getter function that we should probably eliminate"""
nexpaq 0:6c56fb4bc5f0 79 return self.TOOLCHAIN
nexpaq 0:6c56fb4bc5f0 80
nexpaq 0:6c56fb4bc5f0 81 @property
nexpaq 0:6c56fb4bc5f0 82 def flags(self):
nexpaq 0:6c56fb4bc5f0 83 """Returns a dictionary of toolchain flags.
nexpaq 0:6c56fb4bc5f0 84 Keys of the dictionary are:
nexpaq 0:6c56fb4bc5f0 85 cxx_flags - c++ flags
nexpaq 0:6c56fb4bc5f0 86 c_flags - c flags
nexpaq 0:6c56fb4bc5f0 87 ld_flags - linker flags
nexpaq 0:6c56fb4bc5f0 88 asm_flags - assembler flags
nexpaq 0:6c56fb4bc5f0 89 common_flags - common options
nexpaq 0:6c56fb4bc5f0 90 """
nexpaq 0:6c56fb4bc5f0 91 config_header = self.toolchain.get_config_header()
nexpaq 0:6c56fb4bc5f0 92 flags = {key + "_flags": value for key, value
nexpaq 0:6c56fb4bc5f0 93 in self.toolchain.flags.iteritems()}
nexpaq 0:6c56fb4bc5f0 94 asm_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols(True)]
nexpaq 0:6c56fb4bc5f0 95 c_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols()]
nexpaq 0:6c56fb4bc5f0 96 flags['asm_flags'] += asm_defines
nexpaq 0:6c56fb4bc5f0 97 flags['c_flags'] += c_defines
nexpaq 0:6c56fb4bc5f0 98 flags['cxx_flags'] += c_defines
nexpaq 0:6c56fb4bc5f0 99 if config_header:
nexpaq 0:6c56fb4bc5f0 100 config_header = relpath(config_header,
nexpaq 0:6c56fb4bc5f0 101 self.resources.file_basepath[config_header])
nexpaq 0:6c56fb4bc5f0 102 flags['c_flags'] += self.toolchain.get_config_option(config_header)
nexpaq 0:6c56fb4bc5f0 103 flags['cxx_flags'] += self.toolchain.get_config_option(
nexpaq 0:6c56fb4bc5f0 104 config_header)
nexpaq 0:6c56fb4bc5f0 105 return flags
nexpaq 0:6c56fb4bc5f0 106
nexpaq 0:6c56fb4bc5f0 107 def get_source_paths(self):
nexpaq 0:6c56fb4bc5f0 108 """Returns a list of the directories where source files are contained"""
nexpaq 0:6c56fb4bc5f0 109 source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
nexpaq 0:6c56fb4bc5f0 110 'objects', 'libraries']
nexpaq 0:6c56fb4bc5f0 111 source_files = []
nexpaq 0:6c56fb4bc5f0 112 for key in source_keys:
nexpaq 0:6c56fb4bc5f0 113 source_files.extend(getattr(self.resources, key))
nexpaq 0:6c56fb4bc5f0 114 return list(set([os.path.dirname(src) for src in source_files]))
nexpaq 0:6c56fb4bc5f0 115
nexpaq 0:6c56fb4bc5f0 116 def progen_get_project_data(self):
nexpaq 0:6c56fb4bc5f0 117 """ Get ProGen project data """
nexpaq 0:6c56fb4bc5f0 118 # provide default data, some tools don't require any additional
nexpaq 0:6c56fb4bc5f0 119 # tool specific settings
nexpaq 0:6c56fb4bc5f0 120
nexpaq 0:6c56fb4bc5f0 121 def make_key(src):
nexpaq 0:6c56fb4bc5f0 122 """turn a source file into it's group name"""
nexpaq 0:6c56fb4bc5f0 123 key = os.path.basename(os.path.dirname(src))
nexpaq 0:6c56fb4bc5f0 124 if not key:
nexpaq 0:6c56fb4bc5f0 125 key = os.path.basename(os.path.normpath(self.export_dir))
nexpaq 0:6c56fb4bc5f0 126 return key
nexpaq 0:6c56fb4bc5f0 127
nexpaq 0:6c56fb4bc5f0 128 def grouped(sources):
nexpaq 0:6c56fb4bc5f0 129 """Group the source files by their encompassing directory"""
nexpaq 0:6c56fb4bc5f0 130 data = sorted(sources, key=make_key)
nexpaq 0:6c56fb4bc5f0 131 return {k: list(g) for k, g in groupby(data, make_key)}
nexpaq 0:6c56fb4bc5f0 132
nexpaq 0:6c56fb4bc5f0 133 if self.toolchain.get_config_header():
nexpaq 0:6c56fb4bc5f0 134 config_header = self.toolchain.get_config_header()
nexpaq 0:6c56fb4bc5f0 135 config_header = relpath(config_header,
nexpaq 0:6c56fb4bc5f0 136 self.resources.file_basepath[config_header])
nexpaq 0:6c56fb4bc5f0 137 else:
nexpaq 0:6c56fb4bc5f0 138 config_header = None
nexpaq 0:6c56fb4bc5f0 139
nexpaq 0:6c56fb4bc5f0 140 # we want to add this to our include dirs
nexpaq 0:6c56fb4bc5f0 141 config_dir = os.path.dirname(config_header) if config_header else []
nexpaq 0:6c56fb4bc5f0 142
nexpaq 0:6c56fb4bc5f0 143 project_data = tool.get_tool_template()
nexpaq 0:6c56fb4bc5f0 144
nexpaq 0:6c56fb4bc5f0 145 project_data['target'] = TARGET_MAP[self.target].progen['target']
nexpaq 0:6c56fb4bc5f0 146 project_data['source_paths'] = self.get_source_paths()
nexpaq 0:6c56fb4bc5f0 147 project_data['include_paths'] = self.resources.inc_dirs + [config_dir]
nexpaq 0:6c56fb4bc5f0 148 project_data['include_files'] = grouped(self.resources.headers)
nexpaq 0:6c56fb4bc5f0 149 project_data['source_files_s'] = grouped(self.resources.s_sources)
nexpaq 0:6c56fb4bc5f0 150 project_data['source_files_c'] = grouped(self.resources.c_sources)
nexpaq 0:6c56fb4bc5f0 151 project_data['source_files_cpp'] = grouped(self.resources.cpp_sources)
nexpaq 0:6c56fb4bc5f0 152 project_data['source_files_obj'] = grouped(self.resources.objects)
nexpaq 0:6c56fb4bc5f0 153 project_data['source_files_lib'] = grouped(self.resources.libraries)
nexpaq 0:6c56fb4bc5f0 154 project_data['output_dir']['path'] = self.export_dir
nexpaq 0:6c56fb4bc5f0 155 project_data['linker_file'] = self.resources.linker_script
nexpaq 0:6c56fb4bc5f0 156 project_data['macros'] = []
nexpaq 0:6c56fb4bc5f0 157 project_data['build_dir'] = 'build'
nexpaq 0:6c56fb4bc5f0 158 project_data['template'] = None
nexpaq 0:6c56fb4bc5f0 159 project_data['name'] = self.project_name
nexpaq 0:6c56fb4bc5f0 160 project_data['output_type'] = 'exe'
nexpaq 0:6c56fb4bc5f0 161 project_data['debugger'] = None
nexpaq 0:6c56fb4bc5f0 162 return project_data
nexpaq 0:6c56fb4bc5f0 163
nexpaq 0:6c56fb4bc5f0 164 def progen_gen_file(self, project_data):
nexpaq 0:6c56fb4bc5f0 165 """ Generate project using ProGen Project API
nexpaq 0:6c56fb4bc5f0 166 Positional arguments:
nexpaq 0:6c56fb4bc5f0 167 tool_name - the tool for which to generate project files
nexpaq 0:6c56fb4bc5f0 168 project_data - a dict whose base key, values are specified in
nexpaq 0:6c56fb4bc5f0 169 progen_get_project_data, the items will have been
nexpaq 0:6c56fb4bc5f0 170 modified by Exporter subclasses
nexpaq 0:6c56fb4bc5f0 171
nexpaq 0:6c56fb4bc5f0 172 Keyword arguments:
nexpaq 0:6c56fb4bc5f0 173 progen_build - A boolean that determines if the tool will build the
nexpaq 0:6c56fb4bc5f0 174 project
nexpaq 0:6c56fb4bc5f0 175 """
nexpaq 0:6c56fb4bc5f0 176 if not self.check_supported(self.NAME):
nexpaq 0:6c56fb4bc5f0 177 raise TargetNotSupportedException("Target not supported")
nexpaq 0:6c56fb4bc5f0 178 settings = ProjectSettings()
nexpaq 0:6c56fb4bc5f0 179 exporter = ToolsSupported().get_tool(self.NAME)
nexpaq 0:6c56fb4bc5f0 180 self.builder_files_dict = {self.NAME:exporter(project_data, settings).export_project()}
nexpaq 0:6c56fb4bc5f0 181 for middle in self.builder_files_dict.values():
nexpaq 0:6c56fb4bc5f0 182 for field, thing in middle.iteritems():
nexpaq 0:6c56fb4bc5f0 183 if field == "files":
nexpaq 0:6c56fb4bc5f0 184 for filename in thing.values():
nexpaq 0:6c56fb4bc5f0 185 self.generated_files.append(filename)
nexpaq 0:6c56fb4bc5f0 186
nexpaq 0:6c56fb4bc5f0 187 def progen_build(self):
nexpaq 0:6c56fb4bc5f0 188 """Build a project that was already generated by progen"""
nexpaq 0:6c56fb4bc5f0 189 print("Project {} exported, building for {}...".format(
nexpaq 0:6c56fb4bc5f0 190 self.project_name, self.NAME))
nexpaq 0:6c56fb4bc5f0 191 sys.stdout.flush()
nexpaq 0:6c56fb4bc5f0 192 builder = ToolsSupported().get_tool(self.NAME)
nexpaq 0:6c56fb4bc5f0 193 result = builder(self.builder_files_dict[self.NAME], ProjectSettings()).build_project()
nexpaq 0:6c56fb4bc5f0 194 if result == -1:
nexpaq 0:6c56fb4bc5f0 195 raise FailedBuildException("Build Failed")
nexpaq 0:6c56fb4bc5f0 196
nexpaq 0:6c56fb4bc5f0 197 def check_supported(self, ide):
nexpaq 0:6c56fb4bc5f0 198 """Indicated if this combination of IDE and MCU is supported"""
nexpaq 0:6c56fb4bc5f0 199 if self.target not in self.TARGETS or \
nexpaq 0:6c56fb4bc5f0 200 self.TOOLCHAIN not in TARGET_MAP[self.target].supported_toolchains:
nexpaq 0:6c56fb4bc5f0 201 return False
nexpaq 0:6c56fb4bc5f0 202 if not ProGenDef(ide).is_supported(
nexpaq 0:6c56fb4bc5f0 203 TARGET_MAP[self.target].progen['target']):
nexpaq 0:6c56fb4bc5f0 204 return False
nexpaq 0:6c56fb4bc5f0 205 return True
nexpaq 0:6c56fb4bc5f0 206
nexpaq 0:6c56fb4bc5f0 207 def gen_file(self, template_file, data, target_file):
nexpaq 0:6c56fb4bc5f0 208 """Generates a project file from a template using jinja"""
nexpaq 0:6c56fb4bc5f0 209 jinja_loader = FileSystemLoader(
nexpaq 0:6c56fb4bc5f0 210 os.path.dirname(os.path.abspath(__file__)))
nexpaq 0:6c56fb4bc5f0 211 jinja_environment = Environment(loader=jinja_loader)
nexpaq 0:6c56fb4bc5f0 212
nexpaq 0:6c56fb4bc5f0 213 template = jinja_environment.get_template(template_file)
nexpaq 0:6c56fb4bc5f0 214 target_text = template.render(data)
nexpaq 0:6c56fb4bc5f0 215
nexpaq 0:6c56fb4bc5f0 216 target_path = join(self.export_dir, target_file)
nexpaq 0:6c56fb4bc5f0 217 logging.debug("Generating: %s", target_path)
nexpaq 0:6c56fb4bc5f0 218 open(target_path, "w").write(target_text)
nexpaq 0:6c56fb4bc5f0 219 self.generated_files += [target_path]