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.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo by
exporters.py
00001 """Just a template for subclassing""" 00002 import os 00003 import sys 00004 import logging 00005 from os.path import join, dirname, relpath 00006 from itertools import groupby 00007 from jinja2 import FileSystemLoader 00008 from jinja2.environment import Environment 00009 00010 from tools.targets import TARGET_MAP 00011 from project_generator.tools import tool 00012 from project_generator.tools_supported import ToolsSupported 00013 from project_generator.settings import ProjectSettings 00014 from project_generator_definitions.definitions import ProGenDef 00015 00016 00017 class OldLibrariesException (Exception): 00018 """Exception that indicates an export can not complete due to an out of date 00019 library version. 00020 """ 00021 pass 00022 00023 class FailedBuildException (Exception): 00024 """Exception that indicates that a build failed""" 00025 pass 00026 00027 class TargetNotSupportedException (Exception): 00028 """Indicates that an IDE does not support a particular MCU""" 00029 pass 00030 00031 class ExporterTargetsProperty (object): 00032 """ Exporter descriptor for TARGETS 00033 TARGETS as class attribute for backward compatibility 00034 (allows: if in Exporter.TARGETS) 00035 """ 00036 def __init__(self, func): 00037 self.func = func 00038 def __get__(self, inst, cls): 00039 return self.func(cls) 00040 00041 class Exporter (object): 00042 """Exporter base class 00043 00044 This class is meant to be extended by individual exporters, and provides a 00045 few helper methods for implementing an exporter with either jinja2 or 00046 progen. 00047 """ 00048 TEMPLATE_DIR = dirname(__file__) 00049 DOT_IN_RELATIVE_PATH = False 00050 NAME = None 00051 TARGETS = None 00052 TOOLCHAIN = None 00053 00054 def __init__ (self, target, export_dir, project_name, toolchain, 00055 extra_symbols=None, resources=None): 00056 """Initialize an instance of class exporter 00057 Positional arguments: 00058 target - the target mcu/board for this project 00059 export_dir - the directory of the exported project files 00060 project_name - the name of the project 00061 toolchain - an instance of class toolchain 00062 00063 Keyword arguments: 00064 extra_symbols - a list of extra macros for the toolchain 00065 resources - an instance of class Resources 00066 """ 00067 self.export_dir = export_dir 00068 self.target = target 00069 self.project_name = project_name 00070 self.toolchain = toolchain 00071 jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__))) 00072 self.jinja_environment = Environment(loader=jinja_loader) 00073 self.resources = resources 00074 self.generated_files = [] 00075 self.builder_files_dict = {} 00076 00077 def get_toolchain (self): 00078 """A helper getter function that we should probably eliminate""" 00079 return self.TOOLCHAIN 00080 00081 @property 00082 def flags (self): 00083 """Returns a dictionary of toolchain flags. 00084 Keys of the dictionary are: 00085 cxx_flags - c++ flags 00086 c_flags - c flags 00087 ld_flags - linker flags 00088 asm_flags - assembler flags 00089 common_flags - common options 00090 """ 00091 config_header = self.toolchain .get_config_header() 00092 flags = {key + "_flags": value for key, value 00093 in self.toolchain .flags.iteritems()} 00094 asm_defines = ["-D" + symbol for symbol in self.toolchain .get_symbols(True)] 00095 c_defines = ["-D" + symbol for symbol in self.toolchain .get_symbols()] 00096 flags['asm_flags'] += asm_defines 00097 flags['c_flags'] += c_defines 00098 flags['cxx_flags'] += c_defines 00099 if config_header: 00100 config_header = relpath(config_header, 00101 self.resources .file_basepath[config_header]) 00102 flags['c_flags'] += self.toolchain .get_config_option(config_header) 00103 flags['cxx_flags'] += self.toolchain .get_config_option( 00104 config_header) 00105 return flags 00106 00107 def get_source_paths (self): 00108 """Returns a list of the directories where source files are contained""" 00109 source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files', 00110 'objects', 'libraries'] 00111 source_files = [] 00112 for key in source_keys: 00113 source_files.extend(getattr(self.resources , key)) 00114 return list(set([os.path.dirname(src) for src in source_files])) 00115 00116 def progen_get_project_data (self): 00117 """ Get ProGen project data """ 00118 # provide default data, some tools don't require any additional 00119 # tool specific settings 00120 00121 def make_key(src): 00122 """turn a source file into it's group name""" 00123 key = os.path.basename(os.path.dirname(src)) 00124 if not key: 00125 key = os.path.basename(os.path.normpath(self.export_dir )) 00126 return key 00127 00128 def grouped(sources): 00129 """Group the source files by their encompassing directory""" 00130 data = sorted(sources, key=make_key) 00131 return {k: list(g) for k, g in groupby(data, make_key)} 00132 00133 if self.toolchain .get_config_header(): 00134 config_header = self.toolchain .get_config_header() 00135 config_header = relpath(config_header, 00136 self.resources .file_basepath[config_header]) 00137 else: 00138 config_header = None 00139 00140 # we want to add this to our include dirs 00141 config_dir = os.path.dirname(config_header) if config_header else [] 00142 00143 project_data = tool.get_tool_template() 00144 00145 project_data['target'] = TARGET_MAP[self.target ].progen['target'] 00146 project_data['source_paths'] = self.get_source_paths () 00147 project_data['include_paths'] = self.resources .inc_dirs + [config_dir] 00148 project_data['include_files'] = grouped(self.resources .headers) 00149 project_data['source_files_s'] = grouped(self.resources .s_sources) 00150 project_data['source_files_c'] = grouped(self.resources .c_sources) 00151 project_data['source_files_cpp'] = grouped(self.resources .cpp_sources) 00152 project_data['source_files_obj'] = grouped(self.resources .objects) 00153 project_data['source_files_lib'] = grouped(self.resources .libraries) 00154 project_data['output_dir']['path'] = self.export_dir 00155 project_data['linker_file'] = self.resources .linker_script 00156 project_data['macros'] = [] 00157 project_data['build_dir'] = 'build' 00158 project_data['template'] = None 00159 project_data['name'] = self.project_name 00160 project_data['output_type'] = 'exe' 00161 project_data['debugger'] = None 00162 return project_data 00163 00164 def progen_gen_file (self, project_data): 00165 """ Generate project using ProGen Project API 00166 Positional arguments: 00167 tool_name - the tool for which to generate project files 00168 project_data - a dict whose base key, values are specified in 00169 progen_get_project_data, the items will have been 00170 modified by Exporter subclasses 00171 00172 Keyword arguments: 00173 progen_build - A boolean that determines if the tool will build the 00174 project 00175 """ 00176 if not self.check_supported (self.NAME ): 00177 raise TargetNotSupportedException("Target not supported") 00178 settings = ProjectSettings() 00179 exporter = ToolsSupported().get_tool(self.NAME ) 00180 self.builder_files_dict = {self.NAME :exporter(project_data, settings).export_project()} 00181 for middle in self.builder_files_dict .values(): 00182 for field, thing in middle.iteritems(): 00183 if field == "files": 00184 for filename in thing.values(): 00185 self.generated_files .append(filename) 00186 00187 def progen_build (self): 00188 """Build a project that was already generated by progen""" 00189 print("Project {} exported, building for {}...".format( 00190 self.project_name , self.NAME )) 00191 sys.stdout.flush() 00192 builder = ToolsSupported().get_tool(self.NAME ) 00193 result = builder(self.builder_files_dict [self.NAME ], ProjectSettings()).build_project() 00194 if result == -1: 00195 raise FailedBuildException("Build Failed") 00196 00197 def check_supported (self, ide): 00198 """Indicated if this combination of IDE and MCU is supported""" 00199 if self.target not in self.TARGETS or \ 00200 self.TOOLCHAIN not in TARGET_MAP[self.target ].supported_toolchains: 00201 return False 00202 if not ProGenDef(ide).is_supported( 00203 TARGET_MAP[self.target ].progen['target']): 00204 return False 00205 return True 00206 00207 def gen_file (self, template_file, data, target_file): 00208 """Generates a project file from a template using jinja""" 00209 jinja_loader = FileSystemLoader( 00210 os.path.dirname(os.path.abspath(__file__))) 00211 jinja_environment = Environment(loader=jinja_loader) 00212 00213 template = jinja_environment.get_template(template_file) 00214 target_text = template.render(data) 00215 00216 target_path = join(self.export_dir , target_file) 00217 logging.debug("Generating: %s", target_path) 00218 open(target_path, "w").write(target_text) 00219 self.generated_files += [target_path]
Generated on Tue Jul 12 2022 12:28:31 by
1.7.2
