ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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, normpath
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         rel_path = relpath(src, self.resources .file_basepath[src])
00134         path_list = os.path.normpath(rel_path).split(os.sep)
00135         assert path_list >= 1
00136         if len(path_list) == 1:
00137             key = self.project_name 
00138         else:
00139             key = path_list[0]
00140         return key
00141 
00142     def group_project_files (self, sources):
00143         """Group the source files by their encompassing directory
00144         Positional Arguments:
00145         sources - array of source locations
00146 
00147         Returns a dictionary of {group name: list of source locations}
00148         """
00149         data = sorted(sources, key=self.make_key )
00150         return {k: list(g) for k,g in groupby(data, self.make_key )}
00151 
00152     @staticmethod
00153     def build (project_name, log_name='build_log.txt', cleanup=True):
00154         """Invoke exporters build command within a subprocess.
00155         This method is assumed to be executed at the same level as exporter
00156         project files and project source code.
00157         See uvision/__init__.py, iar/__init__.py, and makefile/__init__.py for
00158         example implemenation.
00159 
00160         Positional Arguments:
00161         project_name - the name of the project to build; often required by
00162         exporter's build command.
00163 
00164         Keyword Args:
00165         log_name - name of the build log to create. Written and printed out,
00166         deleted if cleanup = True
00167         cleanup - a boolean dictating whether exported project files and
00168         build log are removed after build
00169 
00170         Returns -1 on failure and 0 on success
00171         """
00172         raise NotImplemented("Implement in derived Exporter class.")
00173 
00174     @abstractmethod
00175     def generate (self):
00176         """Generate an IDE/tool specific project file"""
00177         raise NotImplemented("Implement a generate function in Exporter child class")