Rtos API example

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, StrictUndefined
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 def deprecated_exporter(CLS):
00029     old_init = CLS.__init__
00030     old_name = CLS.NAME
00031     def __init__(*args, **kwargs):
00032         print("==================== DEPRECATION NOTICE ====================")
00033         print("The exporter %s is no longer maintained, and deprecated." % old_name)
00034         print("%s will be removed from mbed OS for the mbed OS 5.6 release." % old_name)
00035         old_init(*args, **kwargs)
00036     CLS.__init__ = __init__
00037     CLS.NAME = "%s (DEPRECATED)" % old_name
00038     return CLS
00039 
00040 class Exporter (object):
00041     """Exporter base class
00042 
00043     This class is meant to be extended by individual exporters, and provides a
00044     few helper methods for implementing an exporter with either jinja2 or
00045     progen.
00046     """
00047     __metaclass__ = ABCMeta
00048     TEMPLATE_DIR = dirname(__file__)
00049     DOT_IN_RELATIVE_PATH = False
00050     NAME = None
00051     TARGETS = set()
00052     TOOLCHAIN = None
00053 
00054 
00055     def __init__ (self, target, export_dir, project_name, toolchain,
00056                  extra_symbols=None, resources=None):
00057         """Initialize an instance of class exporter
00058         Positional arguments:
00059         target        - the target mcu/board for this project
00060         export_dir    - the directory of the exported project files
00061         project_name  - the name of the project
00062         toolchain     - an instance of class toolchain
00063 
00064         Keyword arguments:
00065         extra_symbols - a list of extra macros for the toolchain
00066         resources     - an instance of class Resources
00067         """
00068         self.export_dir  = export_dir
00069         self.target  = target
00070         self.project_name  = project_name
00071         self.toolchain  = toolchain
00072         jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
00073         self.jinja_environment  = Environment(loader=jinja_loader)
00074         self.resources  = resources
00075         self.generated_files  = []
00076         self.static_files  = (
00077             join(self.TEMPLATE_DIR , "GettingStarted.html"),
00078             join(self.TEMPLATE_DIR , ".mbed"),
00079         )
00080         self.builder_files_dict  = {}
00081         self.add_config ()
00082 
00083     def get_toolchain (self):
00084         """A helper getter function that we should probably eliminate"""
00085         return self.TOOLCHAIN 
00086 
00087     def add_config (self):
00088         """Add the containgin directory of mbed_config.h to include dirs"""
00089         config = self.toolchain .get_config_header()
00090         if config:
00091             self.resources .inc_dirs.append(
00092                 dirname(relpath(config,
00093                                 self.resources .file_basepath[config])))
00094 
00095     @property
00096     def flags (self):
00097         """Returns a dictionary of toolchain flags.
00098         Keys of the dictionary are:
00099         cxx_flags    - c++ flags
00100         c_flags      - c flags
00101         ld_flags     - linker flags
00102         asm_flags    - assembler flags
00103         common_flags - common options
00104         """
00105         config_header = self.toolchain .get_config_header()
00106         flags = {key + "_flags": copy.deepcopy(value) for key, value
00107                  in self.toolchain .flags.iteritems()}
00108         asm_defines = self.toolchain .get_compile_options(
00109             self.toolchain .get_symbols(for_asm=True),
00110             filter(None, self.resources .inc_dirs),
00111             for_asm=True)
00112         c_defines = ["-D" + symbol for symbol in self.toolchain .get_symbols()]
00113         flags['asm_flags'] += asm_defines
00114         flags['c_flags'] += c_defines
00115         flags['cxx_flags'] += c_defines
00116         if config_header:
00117             config_header = relpath(config_header,
00118                                     self.resources .file_basepath[config_header])
00119             flags['c_flags'] += self.toolchain .get_config_option(config_header)
00120             flags['cxx_flags'] += self.toolchain .get_config_option(
00121                 config_header)
00122         return flags
00123 
00124     def get_source_paths (self):
00125         """Returns a list of the directories where source files are contained"""
00126         source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
00127                        'objects', 'libraries']
00128         source_files = []
00129         for key in source_keys:
00130             source_files.extend(getattr(self.resources , key))
00131         return list(set([os.path.dirname(src) for src in source_files]))
00132 
00133     def gen_file (self, template_file, data, target_file, **kwargs):
00134         """Generates a project file from a template using jinja"""
00135         jinja_loader = FileSystemLoader(
00136             os.path.dirname(os.path.abspath(__file__)))
00137         jinja_environment = Environment(loader=jinja_loader,
00138                                         undefined=StrictUndefined, **kwargs)
00139 
00140         template = jinja_environment.get_template(template_file)
00141         target_text = template.render(data)
00142 
00143         target_path = join(self.export_dir , target_file)
00144         logging.debug("Generating: %s", target_path)
00145         open(target_path, "w").write(target_text)
00146         self.generated_files  += [target_path]
00147 
00148     def make_key (self, src):
00149         """From a source file, extract group name
00150         Positional Arguments:
00151         src - the src's location
00152         """
00153         rel_path = relpath(src, self.resources .file_basepath[src])
00154         path_list = os.path.normpath(rel_path).split(os.sep)
00155         assert len(path_list) >= 1
00156         if len(path_list) == 1:
00157             key = self.project_name 
00158         else:
00159             key = path_list[0]
00160         return key
00161 
00162     def group_project_files (self, sources):
00163         """Group the source files by their encompassing directory
00164         Positional Arguments:
00165         sources - array of source locations
00166 
00167         Returns a dictionary of {group name: list of source locations}
00168         """
00169         data = sorted(sources, key=self.make_key )
00170         return {k: list(g) for k,g in groupby(data, self.make_key )}
00171 
00172     @staticmethod
00173     def build (project_name, log_name='build_log.txt', cleanup=True):
00174         """Invoke exporters build command within a subprocess.
00175         This method is assumed to be executed at the same level as exporter
00176         project files and project source code.
00177         See uvision/__init__.py, iar/__init__.py, and makefile/__init__.py for
00178         example implemenation.
00179 
00180         Positional Arguments:
00181         project_name - the name of the project to build; often required by
00182         exporter's build command.
00183 
00184         Keyword Args:
00185         log_name - name of the build log to create. Written and printed out,
00186         deleted if cleanup = True
00187         cleanup - a boolean dictating whether exported project files and
00188         build log are removed after build
00189 
00190         Returns -1 on failure and 0 on success
00191         """
00192         raise NotImplemented("Implement in derived Exporter class.")
00193 
00194     @abstractmethod
00195     def generate (self):
00196         """Generate an IDE/tool specific project file"""
00197         raise NotImplemented("Implement a generate function in Exporter child class")
00198 
00199     @classmethod
00200     def is_target_supported (cls, target_name):
00201         """Query support for a particular target
00202 
00203         NOTE: override this method if your exporter does not provide a static list of targets
00204 
00205         Positional Arguments:
00206         target_name - the name of the target.
00207         """
00208         target = TARGET_MAP[target_name]
00209         return bool(set(target.resolution_order_names).intersection(set(cls.TARGETS))) \
00210             and cls.TOOLCHAIN in target.supported_toolchains
00211 
00212 
00213     @classmethod
00214     def all_supported_targets(cls):
00215         return [t for t in TARGET_MAP.keys() if cls.is_target_supported(t)]
00216 
00217 
00218 def apply_supported_whitelist (compiler, whitelist, target):
00219     """Generate a list of supported targets for a given compiler and post-binary hook
00220     white-list."""
00221     if compiler not in target.supported_toolchains:
00222         return False
00223     if not hasattr(target, "post_binary_hook"):
00224         return True
00225     if target.post_binary_hook['function'] in whitelist:
00226         return True
00227     else:
00228         return False