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