Clone of official tools

Revision:
22:9e85236d8716
Parent:
21:4fdf0dd04f6f
Child:
24:25bff2709c20
--- a/toolchains/__init__.py	Fri Jul 15 22:58:15 2016 +0100
+++ b/toolchains/__init__.py	Sat Jul 16 00:34:03 2016 +0100
@@ -210,28 +210,28 @@
     def __init__(self, target, options=None, notify=None, macros=None, silent=False, extra_verbose=False):
         self.target = target
         self.name = self.__class__.__name__
-        
+
         # compile/assemble/link/binary hooks
         self.hook = hooks.Hook(target, self)
 
         # Toolchain flags
         self.flags = deepcopy(self.DEFAULT_FLAGS)
-        
+
         # User-defined macros
         self.macros = macros or []
-        
+
         # Macros generated from toolchain and target rules/features
         self.symbols = None
-        
+
         # Labels generated from toolchain and target rules/features (used for selective build)
         self.labels = None
-        
+
         # This will hold the configuration data (as returned by Config.get_config_data())
         self.config_data = None
 
         # Non-incremental compile
         self.build_all = False
-        
+
         # Build output dir
         self.build_dir = None
         self.timestamp = time()
@@ -242,7 +242,7 @@
         # Number of concurrent build jobs. 0 means auto (based on host system cores)
         self.jobs = 0
 
-        self.CHROOT = None            
+        self.CHROOT = None
 
         # Ignore patterns from .mbedignore files
         self.ignore_patterns = []
@@ -251,18 +251,27 @@
         self.legacy_ignore_dirs = (LEGACY_IGNORE_DIRS | TOOLCHAINS) - set([target.name, LEGACY_TOOLCHAIN_NAMES[self.name]])
 
         # Output notify function
+        # This function is passed all events, and expected to handle notification of the
+        # user, emit the events to a log, etc.
+        # The API for all notify methods passed into the notify parameter is as follows:
+        # def notify(Event, Silent)
+        # Where *Event* is a dict representing the toolchain event that was generated
+        #            e.g.: a compile succeeded, or a warning was emitted by the compiler
+        #                  or an application was linked
+        #       *Silent* is a boolean
         if notify:
             self.notify_fun = notify
         elif extra_verbose:
             self.notify_fun = self.print_notify_verbose
         else:
             self.notify_fun = self.print_notify
-        
+
         # Silent builds (no output)
         self.silent = silent
-        
+
         # Print output buffer
-        self.output = ""
+        self.output = str()
+        self.map_outputs = list()   # Place to store memmap scan results in JSON like data structures
 
         # Build options passed by -o flag
         self.options = options if options is not None else []
@@ -272,7 +281,7 @@
 
         if self.options:
             self.info("Build Options: %s" % (', '.join(self.options)))
-        
+
         # uVisor spepcific rules
         if 'UVISOR' in self.target.features and 'UVISOR_SUPPORTED' in self.target.extra_labels:
             self.target.core = re.sub(r"F$", '', self.target.core)
@@ -295,10 +304,10 @@
 
         if not self.VERBOSE and event['type'] == 'tool_error':
             msg = event['message']
-        
+
         elif event['type'] in ['info', 'debug']:
             msg = event['message']
-            
+
         elif event['type'] == 'cc':
             event['severity'] = event['severity'].title()
             event['file'] = basename(event['file'])
@@ -322,7 +331,6 @@
             event['severity'] = event['severity'].title()
             event['file'] = basename(event['file'])
             event['mcu_name'] = "None"
-            event['toolchain'] = "None"
             event['target_name'] = event['target_name'].upper() if event['target_name'] else "Unknown"
             event['toolchain_name'] = event['toolchain_name'].upper() if event['toolchain_name'] else "Unknown"
             msg = '[%(severity)s] %(target_name)s::%(toolchain_name)s::%(file)s@%(line)s: %(message)s' % event
@@ -335,6 +343,7 @@
     def notify(self, event):
         """ Little closure for notify functions
         """
+        event['toolchain'] = self
         return self.notify_fun(event, self.silent)
 
     def get_symbols(self):
@@ -395,17 +404,14 @@
         for d in dependencies:
             # Some objects are not provided with full path and here we do not have
             # information about the library paths. Safe option: assume an update
-            if not d:
+            if not d or not exists(d):
                 return True
             
-            if self.stat_cache.has_key(d):
-                if self.stat_cache[d] >= target_mod_time:
-                    return True
-            else:
-                if not exists(d): return True
-                
+            if not self.stat_cache.has_key(d):
                 self.stat_cache[d] = stat(d).st_mtime
-                if self.stat_cache[d] >= target_mod_time: return True
+
+            if self.stat_cache[d] >= target_mod_time:
+                return True
         
         return False
 
@@ -597,7 +603,7 @@
 
     def relative_object_path(self, build_path, base_dir, source):
         source_dir, name, _ = split_path(source)
-        
+
         obj_dir = join(build_path, relpath(source_dir, base_dir))
         if obj_dir is not self.prev_dir:
             self.prev_dir = obj_dir
@@ -824,12 +830,12 @@
             if self.target.OUTPUT_NAMING == "8.3":
                 name = name[0:8]
                 ext = ext[0:3]
-        
+
         # Create destination directory
         head, tail =  split(name)
         new_path = join(tmp_path, head)
         mkdir(new_path)
-        
+
         filename = name+'.'+ext
         elf = join(tmp_path, name + '.elf')
         bin = join(tmp_path, filename)
@@ -845,7 +851,7 @@
             self.progress("elf2bin", name)
             self.binary(r, elf, bin)
 
-        self.mem_stats(map)
+        self.map_outputs = self.mem_stats(map)
 
         self.var("compile_succeded", True)
         self.var("binary", filename)
@@ -898,7 +904,11 @@
         self.notify({'type': 'var', 'key': key, 'val': value})
 
     def mem_stats(self, map):
-        # Creates parser object
+        """! Creates parser object
+        @param map Path to linker map file to parse and decode
+        @return Memory summary structure with memory usage statistics
+                None if map file can't be opened and processed
+        """
         toolchain = self.__class__.__name__
 
         # Create memap object
@@ -907,7 +917,7 @@
         # Parse and decode a map file
         if memap.parse(abspath(map), toolchain) is False:
             self.info("Unknown toolchain for memory statistics %s" % toolchain)
-            return
+            return None
 
         # Write output to stdout in text (pretty table) format
         memap.generate_output('table')
@@ -915,11 +925,16 @@
         # Write output to file in JSON format
         map_out = splitext(map)[0] + "_map.json"
         memap.generate_output('json', map_out)
- 
+
         # Write output to file in CSV format for the CI
         map_csv = splitext(map)[0] + "_map.csv"
         memap.generate_output('csv-ci', map_csv)
 
+        # Here we return memory statistics structure (constructed after
+        # call to generate_output) which contains raw data in bytes
+        # about sections + summary
+        return memap.get_memory_summary()
+
     # Set the configuration data
     def set_config_data(self, config_data):
         self.config_data = config_data