Clone of official tools

Revision:
36:96847d42f010
Parent:
35:da9c89f8be7d
Child:
38:399953da035d
--- a/toolchains/__init__.py	Wed Feb 15 13:53:18 2017 -0600
+++ b/toolchains/__init__.py	Thu Jun 22 11:12:28 2017 -0500
@@ -215,7 +215,7 @@
 # standard labels for the "TARGET_" and "TOOLCHAIN_" specific directories, but
 # had the knowledge of a list of these directories to be ignored.
 LEGACY_IGNORE_DIRS = set([
-    'LPC11U24', 'LPC1768', 'LPC2368', 'LPC4088', 'LPC812', 'KL25Z',
+    'LPC11U24', 'LPC1768', 'LPC4088', 'LPC812', 'KL25Z',
     'ARM', 'uARM', 'IAR',
     'GCC_ARM', 'GCC_CS', 'GCC_CR', 'GCC_CW', 'GCC_CW_EWL', 'GCC_CW_NEWLIB',
 ])
@@ -252,11 +252,14 @@
 
     MBED_CONFIG_FILE_NAME="mbed_config.h"
 
+    PROFILE_FILE_NAME = ".profile"
+
     __metaclass__ = ABCMeta
 
     profile_template = {'common':[], 'c':[], 'cxx':[], 'asm':[], 'ld':[]}
 
-    def __init__(self, target, notify=None, macros=None, silent=False, extra_verbose=False, build_profile=None):
+    def __init__(self, target, notify=None, macros=None, silent=False,
+                 extra_verbose=False, build_profile=None, build_dir=None):
         self.target = target
         self.name = self.__class__.__name__
 
@@ -295,12 +298,9 @@
         self.build_all = False
 
         # Build output dir
-        self.build_dir = None
+        self.build_dir = build_dir
         self.timestamp = time()
 
-        # Output build naming based on target+toolchain combo (mbed 2.0 builds)
-        self.obj_path = join("TARGET_"+target.name, "TOOLCHAIN_"+self.name)
-
         # Number of concurrent build jobs. 0 means auto (based on host system cores)
         self.jobs = 0
 
@@ -476,7 +476,7 @@
             # This is a policy decision and it should /really/ be in the config system
             # ATM it's here for backward compatibility
             if ((("-g" in self.flags['common'] or "-g3" in self.flags['common']) and
-                 "-O0") in self.flags['common'] or
+                 "-O0" in self.flags['common']) or
                 ("-r" in self.flags['common'] and
                  "-On" in self.flags['common'])):
                 self.labels['TARGET'].append("DEBUG")
@@ -580,7 +580,8 @@
                     self.add_ignore_patterns(root, base_path, lines)
 
             # Skip the whole folder if ignored, e.g. .mbedignore containing '*'
-            if self.is_ignored(join(relpath(root, base_path),"")):
+            if (self.is_ignored(join(relpath(root, base_path),"")) or
+                self.build_dir == join(relpath(root, base_path))):
                 dirs[:] = []
                 continue
 
@@ -613,6 +614,7 @@
                             break
 
             # Add root to include paths
+            root = root.rstrip("/")
             resources.inc_dirs.append(root)
             resources.file_basepath[root] = base_path
 
@@ -773,7 +775,7 @@
 
     # THIS METHOD IS BEING CALLED BY THE MBED ONLINE BUILD SYSTEM
     # ANY CHANGE OF PARAMETERS OR RETURN VALUES WILL BREAK COMPATIBILITY
-    def compile_sources(self, resources, build_path, inc_dirs=None):
+    def compile_sources(self, resources, inc_dirs=None):
         # Web IDE progress bar for project build
         files_to_compile = resources.s_sources + resources.c_sources + resources.cpp_sources
         self.to_be_compiled = len(files_to_compile)
@@ -790,8 +792,6 @@
         inc_paths = sorted(set(inc_paths))
         # Unique id of all include paths
         self.inc_md5 = md5(' '.join(inc_paths)).hexdigest()
-        # Where to store response files
-        self.build_dir = build_path
 
         objects = []
         queue = []
@@ -800,11 +800,13 @@
 
         # Generate configuration header (this will update self.build_all if needed)
         self.get_config_header()
+        self.dump_build_profile()
 
         # Sort compile queue for consistency
         files_to_compile.sort()
         for source in files_to_compile:
-            object = self.relative_object_path(build_path, resources.file_basepath[source], source)
+            object = self.relative_object_path(
+                self.build_dir, resources.file_basepath[source], source)
 
             # Queue mode (multiprocessing)
             commands = self.compile_command(source, object, inc_paths)
@@ -910,6 +912,13 @@
                 deps = self.parse_dependencies(dep_path) if (exists(dep_path)) else []
             except IOError, IndexError:
                 deps = []
+            config_file = ([self.config.app_config_location]
+                           if self.config.app_config_location else [])
+            deps.extend(config_file)
+            if ext == '.cpp' or self.COMPILE_C_AS_CPP:
+                deps.append(join(self.build_dir, self.PROFILE_FILE_NAME + "-cxx"))
+            else:
+                deps.append(join(self.build_dir, self.PROFILE_FILE_NAME + "-c"))
             if len(deps) == 0 or self.need_update(object, deps):
                 if ext == '.cpp' or self.COMPILE_C_AS_CPP:
                     return self.compile_cpp(source, object, includes)
@@ -917,6 +926,7 @@
                     return self.compile_c(source, object, includes)
         elif ext == '.s':
             deps = [source]
+            deps.append(join(self.build_dir, self.PROFILE_FILE_NAME + "-asm"))
             if self.need_update(object, deps):
                 return self.assemble(source, object, includes)
         else:
@@ -959,7 +969,7 @@
 
     def compile_output(self, output=[]):
         _rc = output[0]
-        _stderr = output[1]
+        _stderr = output[1].decode("utf-8")
         command = output[2]
 
         # Parse output for Warnings and Errors
@@ -1005,16 +1015,20 @@
 
         filename = name+'.'+ext
         elf = join(tmp_path, name + '.elf')
-        bin = join(tmp_path, filename)
+        bin = None if ext is 'elf' else join(tmp_path, filename)
         map = join(tmp_path, name + '.map')
 
         r.objects = sorted(set(r.objects))
-        if self.need_update(elf, r.objects + r.libraries + [r.linker_script]):
+        config_file = ([self.config.app_config_location]
+                       if self.config.app_config_location else [])
+        dependencies = r.objects + r.libraries + [r.linker_script] + config_file
+        dependencies.append(join(self.build_dir, self.PROFILE_FILE_NAME + "-ld"))
+        if self.need_update(elf, dependencies):
             needed_update = True
             self.progress("link", name)
             self.link(elf, r.objects, r.libraries, r.lib_dirs, r.linker_script)
 
-        if self.need_update(bin, [elf]):
+        if bin and self.need_update(bin, [elf]):
             needed_update = True
             self.progress("elf2bin", name)
             self.binary(r, elf, bin)
@@ -1157,6 +1171,22 @@
         self.config_processed = True
         return self.config_file
 
+    def dump_build_profile(self):
+        """Dump the current build profile and macros into the `.profile` file
+        in the build directory"""
+        for key in ["cxx", "c", "asm", "ld"]:
+            to_dump = (str(self.flags[key]) + str(sorted(self.macros)))
+            if key in ["cxx", "c"]:
+                to_dump += str(self.flags['common'])
+            where = join(self.build_dir, self.PROFILE_FILE_NAME + "-" + key)
+            self._overwrite_when_not_equal(where, to_dump)
+
+    @staticmethod
+    def _overwrite_when_not_equal(filename, content):
+        if not exists(filename) or content != open(filename).read():
+            with open(filename, "wb") as out:
+                out.write(content)
+
     @staticmethod
     def generic_check_executable(tool_key, executable_name, levels_up,
                                  nested_dir=None):
@@ -1345,31 +1375,87 @@
         """
         raise NotImplemented
 
+    @staticmethod
+    @abstractmethod
+    def name_mangle(name):
+        """Mangle a name based on the conventional name mangling of this toolchain
+
+        Positional arguments:
+        name -- the name to mangle
+
+        Return:
+        the mangled name as a string
+        """
+        raise NotImplemented
+
+    @staticmethod
+    @abstractmethod
+    def make_ld_define(name, value):
+        """Create an argument to the linker that would define a symbol
+
+        Positional arguments:
+        name -- the symbol to define
+        value -- the value to give the symbol
+
+        Return:
+        The linker flag as a string
+        """
+        raise NotImplemented
+
+    @staticmethod
+    @abstractmethod
+    def redirect_symbol(source, sync, build_dir):
+        """Redirect a symbol at link time to point at somewhere else
+
+        Positional arguments:
+        source -- the symbol doing the pointing
+        sync -- the symbol being pointed to
+        build_dir -- the directory to put "response files" if needed by the toolchain
+
+        Side Effects:
+        Possibly create a file in the build directory
+
+        Return:
+        The linker flag to redirect the symbol, as a string
+        """
+        raise NotImplemented
+
     # Return the list of macros geenrated by the build system
     def get_config_macros(self):
         return Config.config_to_macros(self.config_data) if self.config_data else []
 
+    @property
+    def report(self):
+        to_ret = {}
+        to_ret['c_compiler'] = {'flags': copy(self.flags['c']),
+                                'symbols': self.get_symbols()}
+        to_ret['cxx_compiler'] = {'flags': copy(self.flags['cxx']),
+                                  'symbols': self.get_symbols()}
+        to_ret['assembler'] = {'flags': copy(self.flags['asm']),
+                               'symbols': self.get_symbols(True)}
+        to_ret['linker'] = {'flags': copy(self.flags['ld'])}
+        to_ret.update(self.config.report)
+        return to_ret
+
 from tools.settings import ARM_PATH
-from tools.settings import GCC_ARM_PATH, GCC_CR_PATH
+from tools.settings import GCC_ARM_PATH
 from tools.settings import IAR_PATH
 
 TOOLCHAIN_PATHS = {
     'ARM': ARM_PATH,
     'uARM': ARM_PATH,
     'GCC_ARM': GCC_ARM_PATH,
-    'GCC_CR': GCC_CR_PATH,
     'IAR': IAR_PATH
 }
 
 from tools.toolchains.arm import ARM_STD, ARM_MICRO
-from tools.toolchains.gcc import GCC_ARM, GCC_CR
+from tools.toolchains.gcc import GCC_ARM
 from tools.toolchains.iar import IAR
 
 TOOLCHAIN_CLASSES = {
     'ARM': ARM_STD,
     'uARM': ARM_MICRO,
     'GCC_ARM': GCC_ARM,
-    'GCC_CR': GCC_CR,
     'IAR': IAR
 }