Nicolas Borla / Mbed OS BBR_1Ebene
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm.py Source File

arm.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 from __future__ import print_function, absolute_import
00018 from builtins import str
00019 
00020 import re
00021 from copy import copy
00022 from os.path import join, dirname, splitext, basename, exists, relpath, isfile
00023 from os import makedirs, write, curdir, remove
00024 from tempfile import mkstemp
00025 from shutil import rmtree
00026 
00027 from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
00028 from tools.hooks import hook_tool
00029 from tools.utils import mkdir, NotSupportedException
00030 
00031 class ARM(mbedToolchain):
00032     LINKER_EXT = '.sct'
00033     LIBRARY_EXT = '.ar'
00034 
00035     STD_LIB_NAME = "%s.ar"
00036     DIAGNOSTIC_PATTERN  = re.compile('"(?P<file>[^"]+)", line (?P<line>\d+)( \(column (?P<column>\d+)\)|): (?P<severity>Warning|Error|Fatal error): (?P<message>.+)')
00037     INDEX_PATTERN  = re.compile('(?P<col>\s*)\^')
00038     DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n')
00039     SHEBANG = "#! armcc -E"
00040     SUPPORTED_CORES = ["Cortex-M0", "Cortex-M0+", "Cortex-M3", "Cortex-M4",
00041                        "Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD", "Cortex-A9"]
00042 
00043     @staticmethod
00044     def check_executable():
00045         """Returns True if the executable (armcc) location specified by the
00046          user exists OR the executable can be found on the PATH.
00047          Returns False otherwise."""
00048         return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')
00049 
00050     def __init__(self, target, notify=None, macros=None,
00051                  build_profile=None, build_dir=None):
00052         mbedToolchain.__init__(
00053             self, target, notify, macros, build_dir=build_dir,
00054             build_profile=build_profile)
00055         if target.core not in self.SUPPORTED_CORES:
00056             raise NotSupportedException(
00057                 "this compiler does not support the core %s" % target.core)
00058 
00059         if target.core == "Cortex-M0+":
00060             cpu = "Cortex-M0"
00061         elif target.core == "Cortex-M4F":
00062             cpu = "Cortex-M4.fp"
00063         elif target.core == "Cortex-M7FD":
00064             cpu = "Cortex-M7.fp.dp"
00065         elif target.core == "Cortex-M7F":
00066             cpu = "Cortex-M7.fp.sp"
00067         else:
00068             cpu = target.core
00069 
00070         ARM_BIN = join(TOOLCHAIN_PATHS['ARM'], "bin")
00071         ARM_INC = join(TOOLCHAIN_PATHS['ARM'], "include")
00072 
00073         main_cc = join(ARM_BIN, "armcc")
00074 
00075         self.flags['common'] += ["--cpu=%s" % cpu]
00076 
00077         self.asm = [main_cc] + self.flags['common'] + self.flags['asm']
00078         self.cc = [main_cc] + self.flags['common'] + self.flags['c']
00079         self.cppc = [main_cc] + self.flags['common'] + self.flags['c'] + self.flags['cxx']
00080 
00081         self.ld = [join(ARM_BIN, "armlink")] + self.flags['ld']
00082 
00083         self.ar = join(ARM_BIN, "armar")
00084         self.elf2bin = join(ARM_BIN, "fromelf")
00085 
00086         self.SHEBANG += " --cpu=%s" % cpu
00087 
00088     def parse_dependencies(self, dep_path):
00089         dependencies = []
00090         for line in open(dep_path).readlines():
00091             match = ARM.DEP_PATTERN.match(line)
00092             if match is not None:
00093                 #we need to append chroot, because when the .d files are generated the compiler is chrooted
00094                 dependencies.append((self.CHROOT if self.CHROOT else '') + match.group('file'))
00095         return dependencies
00096 
00097     def parse_output(self, output):
00098         msg = None
00099         for line in output.splitlines():
00100             match = ARM.DIAGNOSTIC_PATTERN.match(line)
00101             if match is not None:
00102                 if msg is not None:
00103                     self.notify.cc_info(msg)
00104                     msg = None
00105                 msg = {
00106                     'severity': match.group('severity').lower(),
00107                     'file': match.group('file'),
00108                     'line': match.group('line'),
00109                     'col': match.group('column') if match.group('column') else 0,
00110                     'message': match.group('message'),
00111                     'text': '',
00112                     'target_name': self.target.name,
00113                     'toolchain_name': self.name
00114                 }
00115             elif msg is not None:
00116                 # Determine the warning/error column by calculating the ^ position
00117                 match = ARM.INDEX_PATTERN.match(line)
00118                 if match is not None:
00119                     msg['col'] = len(match.group('col'))
00120                     self.notify.cc_info(msg)
00121                     msg = None
00122                 else:
00123                     msg['text'] += line+"\n"
00124         
00125         if msg is not None:
00126             self.notify.cc_info(msg)
00127 
00128     def get_dep_option(self, object):
00129         base, _ = splitext(object)
00130         dep_path = base + '.d'
00131         return ["--depend", dep_path]
00132 
00133     def get_config_option(self, config_header):
00134         return ['--preinclude=' + config_header]
00135 
00136     def get_compile_options(self, defines, includes, for_asm=False):
00137         opts = ['-D%s' % d for d in defines]
00138         if for_asm:
00139             return opts
00140         if self.RESPONSE_FILES:
00141             opts += ['--via', self.get_inc_file(includes)]
00142         else:
00143             opts += ["-I%s" % i for i in includes]
00144 
00145         config_header = self.get_config_header()
00146         if config_header is not None:
00147             opts = opts + self.get_config_option(config_header)
00148         return opts
00149 
00150     @hook_tool
00151     def assemble(self, source, object, includes):
00152         # Preprocess first, then assemble
00153         dir = join(dirname(object), '.temp')
00154         mkdir(dir)
00155         tempfile = join(dir, basename(object) + '.E.s')
00156 
00157         # Build preprocess assemble command
00158         cmd_pre = copy(self.asm)
00159         cmd_pre.extend(self.get_compile_options(
00160             self.get_symbols(True), includes, True))
00161         cmd_pre.extend(["-E", "-o", tempfile, source])
00162 
00163         # Build main assemble command
00164         cmd = self.asm + ["-o", object, tempfile]
00165 
00166         # Call cmdline hook
00167         cmd_pre = self.hook.get_cmdline_assembler(cmd_pre)
00168         cmd = self.hook.get_cmdline_assembler(cmd)
00169 
00170         # Return command array, don't execute
00171         return [cmd_pre, cmd]
00172 
00173     @hook_tool
00174     def compile(self, cc, source, object, includes):
00175         # Build compile command
00176         cmd = cc + self.get_compile_options(self.get_symbols(), includes)
00177 
00178         cmd.extend(self.get_dep_option(object))
00179 
00180         cmd.extend(["-o", object, source])
00181 
00182         # Call cmdline hook
00183         cmd = self.hook.get_cmdline_compiler(cmd)
00184 
00185         return [cmd]
00186 
00187     def compile_c(self, source, object, includes):
00188         return self.compile(self.cc, source, object, includes)
00189 
00190     def compile_cpp(self, source, object, includes):
00191         return self.compile(self.cppc, source, object, includes)
00192 
00193     def correct_scatter_shebang(self, scatter_file, base_path=curdir):
00194         """Correct the shebang at the top of a scatter file.
00195 
00196         Positional arguments:
00197         scatter_file -- the scatter file to correct
00198 
00199         Return:
00200         The location of the correct scatter file
00201 
00202         Side Effects:
00203         This method MAY write a new scatter file to disk
00204         """
00205         with open(scatter_file, "r") as input:
00206             lines = input.readlines()
00207             if (lines[0].startswith(self.SHEBANG) or
00208                 not lines[0].startswith("#!")):
00209                 return scatter_file
00210             else:
00211                 new_scatter = join(self.build_dir, ".link_script.sct")
00212                 self.SHEBANG += " -I %s" % relpath(dirname(scatter_file),
00213                                                    base_path)
00214                 if self.need_update(new_scatter, [scatter_file]):
00215                     with open(new_scatter, "w") as out:
00216                         out.write(self.SHEBANG)
00217                         out.write("\n")
00218                         out.write("".join(lines[1:]))
00219 
00220                 return new_scatter
00221 
00222     @hook_tool
00223     def link(self, output, objects, libraries, lib_dirs, scatter_file):
00224         base, _ = splitext(output)
00225         map_file = base + ".map"
00226         args = ["-o", output, "--info=totals", "--map", "--list=%s" % map_file]
00227         args.extend(objects)
00228         args.extend(libraries)
00229         if lib_dirs:
00230             args.extend(["--userlibpath", ",".join(lib_dirs)])
00231         if scatter_file:
00232             new_scatter = self.correct_scatter_shebang(scatter_file)
00233             args.extend(["--scatter", new_scatter])
00234 
00235         cmd_pre = self.ld + args
00236         cmd = self.hook.get_cmdline_linker(cmd_pre)
00237 
00238         if self.RESPONSE_FILES:
00239             cmd_linker = cmd[0]
00240             link_files = self.get_link_file(cmd[1:])
00241             cmd = [cmd_linker, '--via', link_files]
00242 
00243         self.notify.cc_verbose("Link: %s" % ' '.join(cmd))
00244         self.default_cmd(cmd)
00245 
00246     @hook_tool
00247     def archive(self, objects, lib_path):
00248         if self.RESPONSE_FILES:
00249             param = ['--via', self.get_arch_file(objects)]
00250         else:
00251             param = objects
00252         self.default_cmd([self.ar, '-r', lib_path] + param)
00253 
00254     @hook_tool
00255     def binary(self, resources, elf, bin):
00256         _, fmt = splitext(bin)
00257         # On .hex format, combine multiple .hex files (for multiple load regions) into one 
00258         bin_arg = {".bin": "--bin", ".hex": "--i32combined"}[fmt]
00259         cmd = [self.elf2bin, bin_arg, '-o', bin, elf]
00260         cmd = self.hook.get_cmdline_binary(cmd)
00261 
00262         # remove target binary file/path
00263         if exists(bin):
00264             if isfile(bin):
00265                 remove(bin)
00266             else:
00267                 rmtree(bin)
00268 
00269         self.notify.cc_verbose("FromELF: %s" % ' '.join(cmd))
00270         self.default_cmd(cmd)
00271 
00272     @staticmethod
00273     def name_mangle(name):
00274         return "_Z%i%sv" % (len(name), name)
00275 
00276     @staticmethod
00277     def make_ld_define(name, value):
00278         return "--predefine=\"-D%s=0x%x\"" % (name, value)
00279 
00280     @staticmethod
00281     def redirect_symbol(source, sync, build_dir):
00282         if not exists(build_dir):
00283             makedirs(build_dir)
00284         handle, filename = mkstemp(prefix=".redirect-symbol.", dir=build_dir)
00285         write(handle, "RESOLVE %s AS %s\n" % (source, sync))
00286         return "--edit=%s" % filename
00287 
00288 
00289 class ARM_STD(ARM):
00290     def __init__(self, target, notify=None, macros=None,
00291                  build_profile=None, build_dir=None):
00292         ARM.__init__(self, target, notify, macros, build_dir=build_dir,
00293                      build_profile=build_profile)
00294         if "ARM" not in target.supported_toolchains:
00295             raise NotSupportedException("ARM compiler support is required for ARM build")
00296 
00297 
00298 class ARM_MICRO(ARM):
00299     PATCHED_LIBRARY = False
00300     def __init__(self, target, notify=None, macros=None,
00301                  silent=False, extra_verbose=False, build_profile=None,
00302                  build_dir=None):
00303         ARM.__init__(self, target, notify, macros, build_dir=build_dir,
00304                      build_profile=build_profile)
00305         if not set(("ARM", "uARM")).intersection(set(target.supported_toolchains)):
00306             raise NotSupportedException("ARM/uARM compiler support is required for ARM build")
00307 
00308 class ARMC6(ARM_STD):
00309     SHEBANG = "#! armclang -E --target=arm-arm-none-eabi -x c"
00310     SUPPORTED_CORES = ["Cortex-M0", "Cortex-M0+", "Cortex-M3", "Cortex-M4",
00311                        "Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD",
00312                        "Cortex-M23", "Cortex-M23-NS", "Cortex-M33",
00313                        "CortexM33-NS", "Cortex-A9"]
00314     @staticmethod
00315     def check_executable():
00316         return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)
00317 
00318     def __init__(self, target, *args, **kwargs):
00319         mbedToolchain.__init__(self, target, *args, **kwargs)
00320         if target.core not in self.SUPPORTED_CORES:
00321             raise NotSupportedException(
00322                 "this compiler does not support the core %s" % target.core)
00323 
00324         if not set(("ARM", "ARMC6")).intersection(set(target.supported_toolchains)):
00325             raise NotSupportedException("ARM/ARMC6 compiler support is required for ARMC6 build")
00326 
00327         if target.core.lower().endswith("fd"):
00328             self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-2])
00329             self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-2])
00330             self.SHEBANG += " -mcpu=%s" % target.core.lower()[:-2]
00331         elif target.core.lower().endswith("f"):
00332             self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-1])
00333             self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-1])
00334             self.SHEBANG += " -mcpu=%s" % target.core.lower()[:-1]
00335         elif target.core.lower().endswith("ns"):
00336             self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-3])
00337             self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-3])
00338             self.SHEBANG += " -mcpu=%s" % target.core.lower()[:-3]
00339         else:
00340             self.flags['common'].append("-mcpu=%s" % target.core.lower())
00341             self.flags['ld'].append("--cpu=%s" % target.core.lower())
00342             self.SHEBANG += " -mcpu=%s" % target.core.lower()
00343 
00344         if target.core == "Cortex-M4F":
00345             self.flags['common'].append("-mfpu=fpv4-sp-d16")
00346             self.flags['common'].append("-mfloat-abi=hard")
00347         elif target.core == "Cortex-M7F":
00348             self.flags['common'].append("-mfpu=fpv5-sp-d16")
00349             self.flags['common'].append("-mfloat-abi=softfp")
00350         elif target.core == "Cortex-M7FD":
00351             self.flags['common'].append("-mfpu=fpv5-d16")
00352             self.flags['common'].append("-mfloat-abi=softfp")
00353         elif target.core.startswith("Cortex-M23"):
00354             self.flags['common'].append("-march=armv8-m.base")
00355         elif target.core.startswith("Cortex-M33"):
00356             self.flags['common'].append("-march=armv8-m.main")
00357 
00358         if target.core == "Cortex-M23" or target.core == "Cortex-M33":
00359             self.flags['common'].append("-mcmse")
00360 
00361         # Create Secure library
00362         if ((target.core == "Cortex-M23" or self.target.core == "Cortex-M33") and
00363             kwargs.get('build_dir', False)):
00364             build_dir = kwargs['build_dir']
00365             secure_file = join(build_dir, "cmse_lib.o")
00366             self.flags["ld"] += ["--import_cmse_lib_out=%s" % secure_file]
00367         # Add linking time preprocessor macro __DOMAIN_NS
00368         if target.core == "Cortex-M23-NS" or self.target.core == "Cortex-M33-NS":
00369             define_string = self.make_ld_define("__DOMAIN_NS", 1)
00370             self.flags["ld"].append(define_string)
00371 
00372         asm_cpu = {
00373             "Cortex-M0+": "Cortex-M0",
00374             "Cortex-M4F": "Cortex-M4.fp",
00375             "Cortex-M7F": "Cortex-M7.fp.sp",
00376             "Cortex-M7FD": "Cortex-M7.fp.dp",
00377             "Cortex-M23-NS": "Cortex-M23",
00378             "Cortex-M33-NS": "Cortex-M33" }.get(target.core, target.core)
00379 
00380         self.flags['asm'].append("--cpu=%s" % asm_cpu)
00381 
00382         self.cc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
00383                    self.flags['common'] + self.flags['c'])
00384         self.cppc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
00385                      self.flags['common'] + self.flags['cxx'])
00386         self.asm = [join(TOOLCHAIN_PATHS["ARMC6"], "armasm")] + self.flags['asm']
00387         self.ld = [join(TOOLCHAIN_PATHS["ARMC6"], "armlink")] + self.flags['ld']
00388         self.ar = [join(TOOLCHAIN_PATHS["ARMC6"], "armar")]
00389         self.elf2bin = join(TOOLCHAIN_PATHS["ARMC6"], "fromelf")
00390 
00391     def parse_dependencies(self, dep_path):
00392         return mbedToolchain.parse_dependencies(self, dep_path)
00393 
00394     def is_not_supported_error(self, output):
00395         return "#error [NOT_SUPPORTED]" in output
00396 
00397     def parse_output(self, output):
00398         pass
00399 
00400     def get_config_option(self, config_header):
00401         return ["-include", config_header]
00402 
00403     def get_compile_options(self, defines, includes, for_asm=False):
00404         opts = ['-D%s' % d for d in defines]
00405         opts.extend(["-I%s" % i for i in includes])
00406         if for_asm:
00407             return ["--cpreproc",
00408                     "--cpreproc_opts=%s" % ",".join(self.flags['common'] + opts)]
00409         else:
00410             config_header = self.get_config_header()
00411             if config_header:
00412                 opts.extend(self.get_config_option(config_header))
00413             return opts
00414 
00415     @hook_tool
00416     def assemble(self, source, object, includes):
00417         cmd_pre = copy(self.asm)
00418         cmd_pre.extend(self.get_compile_options(
00419             self.get_symbols(True), includes, for_asm=True))
00420         cmd_pre.extend(["-o", object, source])
00421         return [self.hook.get_cmdline_assembler(cmd_pre)]
00422 
00423     @hook_tool
00424     def compile(self, cc, source, object, includes):
00425         cmd = copy(cc)
00426         cmd.extend(self.get_compile_options(self.get_symbols(), includes))
00427         cmd.extend(["-o", object, source])
00428         cmd = self.hook.get_cmdline_compiler(cmd)
00429         return [cmd]