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