Clone of official tools

Revision:
43:2a7da56ebd24
Parent:
42:2cf3f29fece1
--- a/toolchains/arm.py	Mon Nov 06 13:17:14 2017 -0600
+++ b/toolchains/arm.py	Tue Sep 25 13:43:09 2018 -0500
@@ -14,15 +14,21 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 """
+from __future__ import print_function, absolute_import
+from builtins import str
+
 import re
 from copy import copy
-from os.path import join, dirname, splitext, basename, exists
-from os import makedirs, write
+from os.path import join, dirname, splitext, basename, exists, relpath, isfile
+from os import makedirs, write, curdir, remove
 from tempfile import mkstemp
+from shutil import rmtree
+from distutils.version import LooseVersion
 
+from tools.targets import CORE_ARCH
 from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS
 from tools.hooks import hook_tool
-from tools.utils import mkdir, NotSupportedException
+from tools.utils import mkdir, NotSupportedException, run_cmd
 
 class ARM(mbedToolchain):
     LINKER_EXT = '.sct'
@@ -34,7 +40,9 @@
     DEP_PATTERN = re.compile('\S+:\s(?P<file>.+)\n')
     SHEBANG = "#! armcc -E"
     SUPPORTED_CORES = ["Cortex-M0", "Cortex-M0+", "Cortex-M3", "Cortex-M4",
-                       "Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD"]
+                       "Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD", "Cortex-A9"]
+    ARMCC_RANGE = (LooseVersion("5.06"), LooseVersion("5.07"))
+    ARMCC_VERSION_RE = re.compile(b"Component: ARM Compiler (\d+\.\d+)")
 
     @staticmethod
     def check_executable():
@@ -44,16 +52,24 @@
         return mbedToolchain.generic_check_executable("ARM", 'armcc', 2, 'bin')
 
     def __init__(self, target, notify=None, macros=None,
-                 silent=False, extra_verbose=False, build_profile=None,
-                 build_dir=None):
-        mbedToolchain.__init__(self, target, notify, macros, silent,
-                               build_dir=build_dir,
-                               extra_verbose=extra_verbose,
-                               build_profile=build_profile)
+                 build_profile=None, build_dir=None):
+        mbedToolchain.__init__(
+            self, target, notify, macros, build_dir=build_dir,
+            build_profile=build_profile)
         if target.core not in self.SUPPORTED_CORES:
             raise NotSupportedException(
                 "this compiler does not support the core %s" % target.core)
 
+        if getattr(target, "default_lib", "std") == "small":
+            if "-DMBED_RTOS_SINGLE_THREAD" not in self.flags['common']:
+                self.flags['common'].append("-DMBED_RTOS_SINGLE_THREAD")
+            if "-D__MICROLIB" not in self.flags['common']:
+                self.flags['common'].append("-D__MICROLIB")
+            if "--library_type=microlib" not in self.flags['ld']:
+                self.flags['ld'].append("--library_type=microlib")
+            if "--library_type=microlib" not in self.flags['common']:
+                self.flags['common'].append("--library_type=microlib")
+
         if target.core == "Cortex-M0+":
             cpu = "Cortex-M0"
         elif target.core == "Cortex-M4F":
@@ -67,7 +83,7 @@
 
         ARM_BIN = join(TOOLCHAIN_PATHS['ARM'], "bin")
         ARM_INC = join(TOOLCHAIN_PATHS['ARM'], "include")
-        
+
         main_cc = join(ARM_BIN, "armcc")
 
         self.flags['common'] += ["--cpu=%s" % cpu]
@@ -81,6 +97,39 @@
         self.ar = join(ARM_BIN, "armar")
         self.elf2bin = join(ARM_BIN, "fromelf")
 
+        self.SHEBANG += " --cpu=%s" % cpu
+
+    def version_check(self):
+        stdout, _, retcode = run_cmd([self.cc[0], "--vsn"], redirect=True)
+        msg = None
+        min_ver, max_ver = self.ARMCC_RANGE
+        match = self.ARMCC_VERSION_RE.search(stdout)
+        found_version = LooseVersion(match.group(1).decode("utf-8")) if match else None
+        min_ver, max_ver = self.ARMCC_RANGE
+        if found_version and (found_version < min_ver or found_version >= max_ver):
+            msg = ("Compiler version mismatch: Have {}; "
+                   "expected version >= {} and < {}"
+                   .format(found_version, min_ver, max_ver))
+        elif not match or len(match.groups()) != 1:
+            msg = ("Compiler version mismatch: Could not detect version; "
+                   "expected version >= {} and < {}"
+                   .format(min_ver, max_ver))
+
+        if msg:
+            self.notify.cc_info({
+                "message": msg,
+                "file": "",
+                "line": "",
+                "col": "",
+                "severity": "ERROR",
+            })
+
+    def _get_toolchain_labels(self):
+        if getattr(self.target, "default_lib", "std") == "small":
+            return ["ARM", "ARM_MICRO"]
+        else:
+            return ["ARM", "ARM_STD"]
+
     def parse_dependencies(self, dep_path):
         dependencies = []
         for line in open(dep_path).readlines():
@@ -96,7 +145,7 @@
             match = ARM.DIAGNOSTIC_PATTERN.match(line)
             if match is not None:
                 if msg is not None:
-                    self.cc_info(msg)
+                    self.notify.cc_info(msg)
                     msg = None
                 msg = {
                     'severity': match.group('severity').lower(),
@@ -113,13 +162,13 @@
                 match = ARM.INDEX_PATTERN.match(line)
                 if match is not None:
                     msg['col'] = len(match.group('col'))
-                    self.cc_info(msg)
+                    self.notify.cc_info(msg)
                     msg = None
                 else:
                     msg['text'] += line+"\n"
         
         if msg is not None:
-            self.cc_info(msg)
+            self.notify.cc_info(msg)
 
     def get_dep_option(self, object):
         base, _ = splitext(object)
@@ -129,17 +178,18 @@
     def get_config_option(self, config_header):
         return ['--preinclude=' + config_header]
 
-    def get_compile_options(self, defines, includes, for_asm=False):        
+    def get_compile_options(self, defines, includes, for_asm=False):
         opts = ['-D%s' % d for d in defines]
+        config_header = self.get_config_header()
+        if config_header is not None:
+            opts = opts + self.get_config_option(config_header)
+        if for_asm:
+            return opts
         if self.RESPONSE_FILES:
             opts += ['--via', self.get_inc_file(includes)]
         else:
             opts += ["-I%s" % i for i in includes]
 
-        if not for_asm:
-            config_header = self.get_config_header()
-            if config_header is not None:
-                opts = opts + self.get_config_option(config_header)
         return opts
 
     @hook_tool
@@ -148,9 +198,12 @@
         dir = join(dirname(object), '.temp')
         mkdir(dir)
         tempfile = join(dir, basename(object) + '.E.s')
-        
+
         # Build preprocess assemble command
-        cmd_pre = self.asm + self.get_compile_options(self.get_symbols(True), includes) + ["-E", "-o", tempfile, source]
+        cmd_pre = copy(self.asm)
+        cmd_pre.extend(self.get_compile_options(
+            self.get_symbols(True), includes, True))
+        cmd_pre.extend(["-E", "-o", tempfile, source])
 
         # Build main assemble command
         cmd = self.asm + ["-o", object, tempfile]
@@ -158,7 +211,7 @@
         # Call cmdline hook
         cmd_pre = self.hook.get_cmdline_assembler(cmd_pre)
         cmd = self.hook.get_cmdline_assembler(cmd)
-       
+
         # Return command array, don't execute
         return [cmd_pre, cmd]
 
@@ -166,9 +219,9 @@
     def compile(self, cc, source, object, includes):
         # Build compile command
         cmd = cc + self.get_compile_options(self.get_symbols(), includes)
-        
+
         cmd.extend(self.get_dep_option(object))
-            
+
         cmd.extend(["-o", object, source])
 
         # Call cmdline hook
@@ -182,30 +235,38 @@
     def compile_cpp(self, source, object, includes):
         return self.compile(self.cppc, source, object, includes)
 
-    def correct_scatter_shebang(self, scatter_file):
+    def correct_scatter_shebang(self, scatter_file, cur_dir_name=None):
         """Correct the shebang at the top of a scatter file.
 
         Positional arguments:
         scatter_file -- the scatter file to correct
 
+        Keyword arguments:
+        cur_dir_name -- the name (not path) of the directory containing the
+                        scatter file
+
         Return:
         The location of the correct scatter file
 
         Side Effects:
         This method MAY write a new scatter file to disk
         """
-        with open(scatter_file, "rb") as input:
+        with open(scatter_file, "r") as input:
             lines = input.readlines()
-            if  (lines[0].startswith(self.SHEBANG) or
-                 not lines[0].startswith("#!")):
+            if (lines[0].startswith(self.SHEBANG) or
+                not lines[0].startswith("#!")):
                 return scatter_file
             else:
                 new_scatter = join(self.build_dir, ".link_script.sct")
+                if cur_dir_name is None:
+                    cur_dir_name = dirname(scatter_file)
+                self.SHEBANG += " -I %s" % cur_dir_name
                 if self.need_update(new_scatter, [scatter_file]):
-                    with open(new_scatter, "wb") as out:
+                    with open(new_scatter, "w") as out:
                         out.write(self.SHEBANG)
                         out.write("\n")
                         out.write("".join(lines[1:]))
+
                 return new_scatter
 
     @hook_tool
@@ -229,7 +290,7 @@
             link_files = self.get_link_file(cmd[1:])
             cmd = [cmd_linker, '--via', link_files]
 
-        self.cc_verbose("Link: %s" % ' '.join(cmd))
+        self.notify.cc_verbose("Link: %s" % ' '.join(cmd))
         self.default_cmd(cmd)
 
     @hook_tool
@@ -243,10 +304,19 @@
     @hook_tool
     def binary(self, resources, elf, bin):
         _, fmt = splitext(bin)
-        bin_arg = {".bin": "--bin", ".hex": "--i32"}[fmt]
+        # On .hex format, combine multiple .hex files (for multiple load regions) into one 
+        bin_arg = {".bin": "--bin", ".hex": "--i32combined"}[fmt]
         cmd = [self.elf2bin, bin_arg, '-o', bin, elf]
         cmd = self.hook.get_cmdline_binary(cmd)
-        self.cc_verbose("FromELF: %s" % ' '.join(cmd))
+
+        # remove target binary file/path
+        if exists(bin):
+            if isfile(bin):
+                remove(bin)
+            else:
+                rmtree(bin)
+
+        self.notify.cc_verbose("FromELF: %s" % ' '.join(cmd))
         self.default_cmd(cmd)
 
     @staticmethod
@@ -255,7 +325,7 @@
 
     @staticmethod
     def make_ld_define(name, value):
-        return "--predefine=\"-D%s=0x%x\"" % (name, value)
+        return "--predefine=\"-D%s=%s\"" % (name, value)
 
     @staticmethod
     def redirect_symbol(source, sync, build_dir):
@@ -268,13 +338,11 @@
 
 class ARM_STD(ARM):
     def __init__(self, target, notify=None, macros=None,
-                 silent=False, extra_verbose=False, build_profile=None,
-                 build_dir=None):
-        ARM.__init__(self, target, notify, macros, silent,
-                     build_dir=build_dir, extra_verbose=extra_verbose,
+                 build_profile=None, build_dir=None):
+        ARM.__init__(self, target, notify, macros, build_dir=build_dir,
                      build_profile=build_profile)
-        if "ARM" not in target.supported_toolchains:
-            raise NotSupportedException("ARM compiler support is required for ARM build")
+        if not set(("ARM", "uARM")).intersection(set(target.supported_toolchains)):
+            raise NotSupportedException("ARM/uARM compiler support is required for ARM build")
 
 
 class ARM_MICRO(ARM):
@@ -282,8 +350,8 @@
     def __init__(self, target, notify=None, macros=None,
                  silent=False, extra_verbose=False, build_profile=None,
                  build_dir=None):
-        ARM.__init__(self, target, notify, macros, silent,
-                     build_dir=build_dir, extra_verbose=extra_verbose,
+        target.default_lib = "small"
+        ARM.__init__(self, target, notify, macros, build_dir=build_dir,
                      build_profile=build_profile)
         if not set(("ARM", "uARM")).intersection(set(target.supported_toolchains)):
             raise NotSupportedException("ARM/uARM compiler support is required for ARM build")
@@ -293,7 +361,9 @@
     SUPPORTED_CORES = ["Cortex-M0", "Cortex-M0+", "Cortex-M3", "Cortex-M4",
                        "Cortex-M4F", "Cortex-M7", "Cortex-M7F", "Cortex-M7FD",
                        "Cortex-M23", "Cortex-M23-NS", "Cortex-M33",
-                       "CortexM33-NS"]
+                       "Cortex-M33-NS", "Cortex-A9"]
+    ARMCC_RANGE = (LooseVersion("6.10"), LooseVersion("7.0"))
+
     @staticmethod
     def check_executable():
         return mbedToolchain.generic_check_executable("ARMC6", "armclang", 1)
@@ -303,6 +373,14 @@
         if target.core not in self.SUPPORTED_CORES:
             raise NotSupportedException(
                 "this compiler does not support the core %s" % target.core)
+        if CORE_ARCH[target.core] < 8:
+            self.notify.cc_info({
+                'severity': "Error", 'file': "", 'line': "", 'col': "",
+                'message': "ARMC6 does not support ARM architecture v{}"
+                " targets".format(CORE_ARCH[target.core]),
+                'text': '', 'target_name': self.target.name,
+                'toolchain_name': self.name
+            })
 
         if not set(("ARM", "ARMC6")).intersection(set(target.supported_toolchains)):
             raise NotSupportedException("ARM/ARMC6 compiler support is required for ARMC6 build")
@@ -310,15 +388,19 @@
         if target.core.lower().endswith("fd"):
             self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-2])
             self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-2])
+            self.SHEBANG += " -mcpu=%s" % target.core.lower()[:-2]
         elif target.core.lower().endswith("f"):
             self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-1])
             self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-1])
-        elif target.core.lower().endswith("ns"):
-            self.flags['common'].append("-mcpu=%s" % target.core.lower()[:-3])
-            self.flags['ld'].append("--cpu=%s" % target.core.lower()[:-3])
-        else:
+            self.SHEBANG += " -mcpu=%s" % target.core.lower()[:-1]
+        elif target.core.startswith("Cortex-M33"):
+            self.flags['common'].append("-mcpu=cortex-m33+nodsp")
+            self.flags['common'].append("-mfpu=none")
+            self.flags['ld'].append("--cpu=Cortex-M33.no_dsp.no_fp")
+        elif not target.core.startswith("Cortex-M23"):
             self.flags['common'].append("-mcpu=%s" % target.core.lower())
             self.flags['ld'].append("--cpu=%s" % target.core.lower())
+            self.SHEBANG += " -mcpu=%s" % target.core.lower()
 
         if target.core == "Cortex-M4F":
             self.flags['common'].append("-mfpu=fpv4-sp-d16")
@@ -331,11 +413,21 @@
             self.flags['common'].append("-mfloat-abi=softfp")
         elif target.core.startswith("Cortex-M23"):
             self.flags['common'].append("-march=armv8-m.base")
-        elif target.core.startswith("Cortex-M33"):
-            self.flags['common'].append("-march=armv8-m.main")
 
         if target.core == "Cortex-M23" or target.core == "Cortex-M33":
-            self.flags['common'].append("-mcmse")
+            self.flags['cxx'].append("-mcmse")
+            self.flags['c'].append("-mcmse")
+
+        # Create Secure library
+        if ((target.core == "Cortex-M23" or self.target.core == "Cortex-M33") and
+            kwargs.get('build_dir', False)):
+            build_dir = kwargs['build_dir']
+            secure_file = join(build_dir, "cmse_lib.o")
+            self.flags["ld"] += ["--import_cmse_lib_out=%s" % secure_file]
+        # Add linking time preprocessor macro __DOMAIN_NS
+        if target.core == "Cortex-M23-NS" or self.target.core == "Cortex-M33-NS":
+            define_string = self.make_ld_define("__DOMAIN_NS", "0x1")
+            self.flags["ld"].append(define_string)
 
         asm_cpu = {
             "Cortex-M0+": "Cortex-M0",
@@ -345,7 +437,10 @@
             "Cortex-M23-NS": "Cortex-M23",
             "Cortex-M33-NS": "Cortex-M33" }.get(target.core, target.core)
 
-        self.flags['asm'].append("--cpu=%s" % asm_cpu)
+        if target.core.startswith("Cortex-M33"):
+            self.flags['asm'].append("--cpu=Cortex-M33.no_dsp.no_fp")
+        else :
+            self.flags['asm'].append("--cpu=%s" % asm_cpu)
 
         self.cc = ([join(TOOLCHAIN_PATHS["ARMC6"], "armclang")] +
                    self.flags['common'] + self.flags['c'])
@@ -356,6 +451,8 @@
         self.ar = [join(TOOLCHAIN_PATHS["ARMC6"], "armar")]
         self.elf2bin = join(TOOLCHAIN_PATHS["ARMC6"], "fromelf")
 
+    def _get_toolchain_labels(self):
+        return ["ARM", "ARM_STD", "ARMC6"]
 
     def parse_dependencies(self, dep_path):
         return mbedToolchain.parse_dependencies(self, dep_path)