Anders Blomdell / mbed-sdk-tools
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers iar.py Source File

iar.py

00001 """
00002 mbed SDK
00003 Copyright (c) 2011-2013 ARM Limited
00004 
00005 Licensed under the Apache License, Version 2.0 (the "License");
00006 you may not use this file except in compliance with the License.
00007 You may obtain a copy of the License at
00008 
00009     http://www.apache.org/licenses/LICENSE-2.0
00010 
00011 Unless required by applicable law or agreed to in writing, software
00012 distributed under the License is distributed on an "AS IS" BASIS,
00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 See the License for the specific language governing permissions and
00015 limitations under the License.
00016 """
00017 import re
00018 from os import remove
00019 from os.path import join, splitext, exists
00020 from distutils.version import LooseVersion
00021 
00022 from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
00023 from tools.hooks import hook_tool
00024 from tools.utils import run_cmd, NotSupportedException
00025 
00026 class IAR(mbedToolchain):
00027     LIBRARY_EXT = '.a'
00028     LINKER_EXT = '.icf'
00029     STD_LIB_NAME = "%s.a"
00030 
00031     DIAGNOSTIC_PATTERN = re.compile('"(?P<file>[^"]+)",(?P<line>[\d]+)\s+(?P<severity>Warning|Error|Fatal error)(?P<message>.+)')
00032     INDEX_PATTERN  = re.compile('(?P<col>\s*)\^')
00033     IAR_VERSION_RE = re.compile(b"IAR ANSI C/C\+\+ Compiler V(\d+\.\d+)")
00034     IAR_VERSION = LooseVersion("7.80")
00035 
00036     @staticmethod
00037     def check_executable():
00038         """Returns True if the executable (arm-none-eabi-gcc) location
00039         specified by the user exists OR the executable can be found on the PATH.
00040         Returns False otherwise."""
00041         return mbedToolchain.generic_check_executable("IAR", 'iccarm', 2, "bin")
00042 
00043     def __init__(self, target, notify=None, macros=None, build_profile=None,
00044                  build_dir=None):
00045         mbedToolchain.__init__(self, target, notify, macros, build_dir=build_dir,
00046                                build_profile=build_profile)
00047         if target.core == "Cortex-M7F" or target.core == "Cortex-M7FD":
00048             cpuchoice = "Cortex-M7"
00049         elif target.core.startswith("Cortex-M23"):
00050             cpuchoice = "8-M.baseline"
00051         elif target.core.startswith("Cortex-M33"):
00052             cpuchoice = "8-M.mainline"
00053         else:
00054             cpuchoice = target.core
00055 
00056         # flags_cmd are used only by our scripts, the project files have them already defined,
00057         # using this flags results in the errors (duplication)
00058         # asm accepts --cpu Core or --fpu FPU, not like c/c++ --cpu=Core
00059         asm_flags_cmd = ["--cpu", cpuchoice]
00060         # custom c flags
00061         c_flags_cmd = ["--cpu", cpuchoice]
00062 
00063         c_flags_cmd.extend([
00064             "--thumb", "--dlib_config", "DLib_Config_Full.h"
00065         ])
00066         # custom c++ cmd flags
00067         cxx_flags_cmd = [
00068             "--c++", "--no_rtti", "--no_exceptions"
00069         ]
00070         if target.core == "Cortex-M7FD":
00071             asm_flags_cmd += ["--fpu", "VFPv5"]
00072             c_flags_cmd.append("--fpu=VFPv5")
00073         elif target.core == "Cortex-M7F":
00074             asm_flags_cmd += ["--fpu", "VFPv5_sp"]
00075             c_flags_cmd.append("--fpu=VFPv5_sp")
00076         elif target.core == "Cortex-M23" or target.core == "Cortex-M33":
00077             self.flags["asm"] += ["--cmse"]
00078             self.flags["common"] += ["--cmse"]
00079 
00080         # Create Secure library
00081         if target.core == "Cortex-M23" or self.target.core == "Cortex-M33":
00082             secure_file = join(build_dir, "cmse_lib.o")
00083             self.flags["ld"] += ["--import_cmse_lib_out=%s" % secure_file]
00084 
00085         IAR_BIN = join(TOOLCHAIN_PATHS['IAR'], "bin")
00086         main_cc = join(IAR_BIN, "iccarm")
00087 
00088         self.asm  = [join(IAR_BIN, "iasmarm")] + asm_flags_cmd + self.flags["asm"]
00089         self.cc   = [main_cc]
00090         self.cppc = [main_cc]
00091         self.cc += self.flags["common"] + c_flags_cmd + self.flags["c"]
00092         self.cppc += self.flags["common"] + c_flags_cmd + cxx_flags_cmd + self.flags["cxx"]
00093         
00094         self.ld   = [join(IAR_BIN, "ilinkarm")] + self.flags['ld']
00095         self.ar = join(IAR_BIN, "iarchive")
00096         self.elf2bin = join(IAR_BIN, "ielftool")
00097 
00098     def version_check(self):
00099         stdout, _, retcode = run_cmd([self.cc[0], "--version"], redirect=True)
00100         msg = None
00101         match = self.IAR_VERSION_RE.search(stdout)
00102         found_version = match.group(1).decode("utf-8") if match else None
00103         if found_version and LooseVersion(found_version) != self.IAR_VERSION:
00104             msg = "Compiler version mismatch: Have {}; expected {}".format(
00105                 found_version, self.IAR_VERSION)
00106         elif not match or len(match.groups()) != 1:
00107             msg = ("Compiler version mismatch: Could Not detect compiler "
00108                    "version; expected {}".format(self.IAR_VERSION))
00109         if msg:
00110             self.notify.cc_info({
00111                 "message": msg,
00112                 "file": "",
00113                 "line": "",
00114                 "col": "",
00115                 "severity": "ERROR",
00116             })
00117 
00118 
00119     def parse_dependencies(self, dep_path):
00120         return [(self.CHROOT if self.CHROOT else '')+path.strip() for path in open(dep_path).readlines()
00121                 if (path and not path.isspace())]
00122 
00123     def parse_output(self, output):
00124         msg = None
00125         for line in output.splitlines():
00126             match = IAR.DIAGNOSTIC_PATTERN.match(line)
00127             if match is not None:
00128                 if msg is not None:
00129                     self.notify.cc_info(msg)
00130                     msg = None
00131                 msg = {
00132                     'severity': match.group('severity').lower(),
00133                     'file': match.group('file'),
00134                     'line': match.group('line'),
00135                     'col': 0,
00136                     'message': match.group('message'),
00137                     'text': '',
00138                     'target_name': self.target.name,
00139                     'toolchain_name': self.name
00140                 }
00141             elif msg is not None:
00142                 # Determine the warning/error column by calculating the ^ position
00143                 match = IAR.INDEX_PATTERN.match(line)
00144                 if match is not None:
00145                     msg['col'] = len(match.group('col'))
00146                     self.notify.cc_info(msg)
00147                     msg = None
00148                 else:
00149                     msg['text'] += line+"\n"
00150 
00151         if msg is not None:
00152             self.notify.cc_info(msg)
00153 
00154     def get_dep_option(self, object):
00155         base, _ = splitext(object)
00156         dep_path = base + '.d'
00157         return ["--dependencies", dep_path]
00158 
00159     def cc_extra(self, object):
00160         base, _ = splitext(object)
00161         return ["-l", base + '.s.txt']
00162 
00163     def get_config_option(self, config_header):
00164         return ['--preinclude=' + config_header]
00165 
00166     def get_compile_options(self, defines, includes, for_asm=False):
00167         opts = ['-D%s' % d for d in defines]
00168         if for_asm:
00169             config_macros = self.config.get_config_data_macros()
00170             macros_cmd = ['"-D%s"' % d.replace('"', '').replace('//','/\/') for d in config_macros]
00171             if self.RESPONSE_FILES:
00172                 via_file = self.make_option_file(
00173                     macros_cmd, "asm_macros_{}.xcl")
00174                 opts += ['-f', via_file]
00175             else:
00176                 opts += macros_cmd
00177             return opts
00178         else:
00179             if self.RESPONSE_FILES:
00180                 opts += ['-f', self.get_inc_file(includes)]
00181             else:
00182                 opts += ["-I%s" % i for i in includes]
00183             config_header = self.get_config_header()
00184             if config_header is not None:
00185                 opts = opts + self.get_config_option(config_header)
00186 
00187             return opts
00188 
00189     @hook_tool
00190     def assemble(self, source, object, includes):
00191         # Build assemble command
00192         cmd = self.asm + self.get_compile_options(self.get_symbols(True), includes, True) + ["-o", object, source]
00193 
00194         # Call cmdline hook
00195         cmd = self.hook.get_cmdline_assembler(cmd)
00196 
00197         # Return command array, don't execute
00198         return [cmd]
00199 
00200     @hook_tool
00201     def compile(self, cc, source, object, includes):
00202         # Build compile command
00203         cmd = cc +  self.get_compile_options(self.get_symbols(), includes)
00204 
00205         cmd.extend(self.get_dep_option(object))
00206 
00207         cmd.extend(self.cc_extra(object))
00208         
00209         cmd.extend(["-o", object, source])
00210 
00211         # Call cmdline hook
00212         cmd = self.hook.get_cmdline_compiler(cmd)
00213 
00214         return [cmd]
00215 
00216     def compile_c(self, source, object, includes):
00217         return self.compile(self.cc, source, object, includes)
00218 
00219     def compile_cpp(self, source, object, includes):
00220         return self.compile(self.cppc, source, object, includes)
00221 
00222     @hook_tool
00223     def link(self, output, objects, libraries, lib_dirs, mem_map):
00224         # Build linker command
00225         map_file = splitext(output)[0] + ".map"
00226         cmd = self.ld + [ "-o", output, "--map=%s" % map_file] + objects + libraries
00227 
00228         if mem_map:
00229             cmd.extend(["--config", mem_map])
00230 
00231         # Call cmdline hook
00232         cmd = self.hook.get_cmdline_linker(cmd)
00233 
00234         if self.RESPONSE_FILES:
00235             # Split link command to linker executable + response file
00236             cmd_linker = cmd[0]
00237             link_files = self.get_link_file(cmd[1:])
00238             cmd = [cmd_linker, '-f', link_files]
00239 
00240         # Exec command
00241         self.notify.cc_verbose("Link: %s" % ' '.join(cmd))
00242         self.default_cmd(cmd)
00243 
00244     @hook_tool
00245     def archive(self, objects, lib_path):
00246         if self.RESPONSE_FILES:
00247             param = ['-f', self.get_arch_file(objects)]
00248         else:
00249             param = objects
00250 
00251         if exists(lib_path):
00252             remove(lib_path)
00253 
00254         self.default_cmd([self.ar, lib_path] + param)
00255 
00256     @hook_tool
00257     def binary(self, resources, elf, bin):
00258         _, fmt = splitext(bin)
00259         bin_arg = {".bin": "--bin", ".hex": "--ihex"}[fmt]
00260         # Build binary command
00261         cmd = [self.elf2bin, bin_arg, elf, bin]
00262 
00263         # Call cmdline hook
00264         cmd = self.hook.get_cmdline_binary(cmd)
00265 
00266         # Exec command
00267         self.notify.cc_verbose("FromELF: %s" % ' '.join(cmd))
00268         self.default_cmd(cmd)
00269 
00270     @staticmethod
00271     def name_mangle(name):
00272         return "_Z%i%sv" % (len(name), name)
00273 
00274     @staticmethod
00275     def make_ld_define(name, value):
00276         return "--config_def %s=%s" % (name, value)
00277 
00278     @staticmethod
00279     def redirect_symbol(source, sync, build_dir):
00280         return "--redirect %s=%s" % (source, sync)