Greg Steiert / pegasus_dev

Dependents:   blinky_max32630fthr

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers exporters.py Source File

exporters.py

00001 """Just a template for subclassing"""
00002 import os
00003 from abc import abstractmethod, ABCMeta
00004 import logging
00005 from os.path import join, dirname, relpath, basename, realpath
00006 from itertools import groupby
00007 from jinja2 import FileSystemLoader
00008 from jinja2.environment import Environment
00009 import copy
00010 
00011 from tools.targets import TARGET_MAP
00012 
00013 
00014 class TargetNotSupportedException (Exception):
00015     """Indicates that an IDE does not support a particular MCU"""
00016     pass
00017 
00018 class ExporterTargetsProperty (object):
00019     """ Exporter descriptor for TARGETS
00020     TARGETS as class attribute for backward compatibility
00021     (allows: if in Exporter.TARGETS)
00022     """
00023     def __init__(self, func):
00024         self.func = func
00025     def __get__(self, inst, cls):
00026         return self.func(cls)
00027 
00028 class Exporter (object):
00029     """Exporter base class
00030 
00031     This class is meant to be extended by individual exporters, and provides a
00032     few helper methods for implementing an exporter with either jinja2 or
00033     progen.
00034     """
00035     __metaclass__ = ABCMeta
00036     TEMPLATE_DIR = dirname(__file__)
00037     DOT_IN_RELATIVE_PATH = False
00038     NAME = None
00039     TARGETS = None
00040     TOOLCHAIN = None
00041 
00042 
00043     def __init__ (self, target, export_dir, project_name, toolchain,
00044                  extra_symbols=None, resources=None):
00045         """Initialize an instance of class exporter
00046         Positional arguments:
00047         target        - the target mcu/board for this project
00048         export_dir    - the directory of the exported project files
00049         project_name  - the name of the project
00050         toolchain     - an instance of class toolchain
00051 
00052         Keyword arguments:
00053         extra_symbols - a list of extra macros for the toolchain
00054         resources     - an instance of class Resources
00055         """
00056         self.export_dir  = export_dir
00057         self.target  = target
00058         self.project_name  = project_name
00059         self.toolchain  = toolchain
00060         jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
00061         self.jinja_environment  = Environment(loader=jinja_loader)
00062         self.resources  = resources
00063         self.generated_files  = [join(self.TEMPLATE_DIR ,"GettingStarted.html")]
00064         self.builder_files_dict  = {}
00065         self.add_config ()
00066 
00067     def get_toolchain (self):
00068         """A helper getter function that we should probably eliminate"""
00069         return self.TOOLCHAIN 
00070 
00071     def add_config (self):
00072         """Add the containgin directory of mbed_config.h to include dirs"""
00073         config = self.toolchain .get_config_header()
00074         if config:
00075             self.resources .inc_dirs.append(
00076                 dirname(relpath(config,
00077                                 self.resources .file_basepath[config])))
00078 
00079     @property
00080     def flags (self):
00081         """Returns a dictionary of toolchain flags.
00082         Keys of the dictionary are:
00083         cxx_flags    - c++ flags
00084         c_flags      - c flags
00085         ld_flags     - linker flags
00086         asm_flags    - assembler flags
00087         common_flags - common options
00088         """
00089         config_header = self.toolchain .get_config_header()
00090         flags = {key + "_flags": copy.deepcopy(value) for key, value
00091                  in self.toolchain .flags.iteritems()}
00092         asm_defines = ["-D" + symbol for symbol in self.toolchain .get_symbols(True)]
00093         c_defines = ["-D" + symbol for symbol in self.toolchain .get_symbols()]
00094         flags['asm_flags'] += asm_defines
00095         flags['c_flags'] += c_defines
00096         flags['cxx_flags'] += c_defines
00097         if config_header:
00098             config_header = relpath(config_header,
00099                                     self.resources .file_basepath[config_header])
00100             flags['c_flags'] += self.toolchain .get_config_option(config_header)
00101             flags['cxx_flags'] += self.toolchain .get_config_option(
00102                 config_header)
00103         return flags
00104 
00105     def get_source_paths (self):
00106         """Returns a list of the directories where source files are contained"""
00107         source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
00108                        'objects', 'libraries']
00109         source_files = []
00110         for key in source_keys:
00111             source_files.extend(getattr(self.resources , key))
00112         return list(set([os.path.dirname(src) for src in source_files]))
00113 
00114     def gen_file (self, template_file, data, target_file):
00115         """Generates a project file from a template using jinja"""
00116         jinja_loader = FileSystemLoader(
00117             os.path.dirname(os.path.abspath(__file__)))
00118         jinja_environment = Environment(loader=jinja_loader)
00119 
00120         template = jinja_environment.get_template(template_file)
00121         target_text = template.render(data)
00122 
00123         target_path = join(self.export_dir , target_file)
00124         logging.debug("Generating: %s", target_path)
00125         open(target_path, "w").write(target_text)
00126         self.generated_files  += [target_path]
00127 
00128     def make_key (self, src):
00129         """From a source file, extract group name
00130         Positional Arguments:
00131         src - the src's location
00132         """
00133         key = basename(dirname(src))
00134         if key == ".":
00135             key = basename(realpath(self.export_dir ))
00136         return key
00137 
00138     def group_project_files (self, sources):
00139         """Group the source files by their encompassing directory
00140         Positional Arguments:
00141         sources - array of source locations
00142 
00143         Returns a dictionary of {group name: list of source locations}
00144         """
00145         data = sorted(sources, key=self.make_key )
00146         return {k: list(g) for k,g in groupby(data, self.make_key )}
00147 
00148     @staticmethod
00149     def build (project_name, log_name='build_log.txt', cleanup=True):
00150         """Invoke exporters build command within a subprocess.
00151         This method is assumed to be executed at the same level as exporter
00152         project files and project source code.
00153         See uvision/__init__.py, iar/__init__.py, and makefile/__init__.py for
00154         example implemenation.
00155 
00156         Positional Arguments:
00157         project_name - the name of the project to build; often required by
00158         exporter's build command.
00159 
00160         Keyword Args:
00161         log_name - name of the build log to create. Written and printed out,
00162         deleted if cleanup = True
00163         cleanup - a boolean dictating whether exported project files and
00164         build log are removed after build
00165 
00166         Returns -1 on failure and 0 on success
00167         """
00168         raise NotImplemented("Implement in derived Exporter class.")
00169 
00170     @abstractmethod
00171     def generate (self):
00172         """Generate an IDE/tool specific project file"""
00173         raise NotImplemented("Implement a generate function in Exporter child class")