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