Added local C dependency dicovery and changes checking, to speed up build.
authoretisserant
Sun, 04 Jan 2009 17:25:22 +0100
changeset 285 e5782a52dcea
parent 284 3fecc96090c8
child 286 a2a8a52b0d4f
Added local C dependency dicovery and changes checking, to speed up build.
targets/toolchain_gcc.py
--- a/targets/toolchain_gcc.py	Tue Dec 30 22:47:15 2008 +0100
+++ b/targets/toolchain_gcc.py	Sun Jan 04 17:25:22 2009 +0100
@@ -1,7 +1,9 @@
-import os
+import os, re, operator
 from wxPopen import ProcessLogger
 import hashlib
 
+includes_re =  re.compile('\s*#include\s*["<]([^">]*)[">].*')
+
 class toolchain_gcc():
     """
     This abstract class contains GCC specific code.
@@ -15,6 +17,7 @@
         self.buildpath = PuginsRootInstance._getBuildPath()
         self.exe_path = os.path.join(self.buildpath, self.exe)
         self.md5key = None
+        self.srcmd5 = {}
 
     def GetBinaryCode(self):
         try:
@@ -33,8 +36,33 @@
                 return open(self._GetMD5FileName(), "r").read()
             except Exception, e:
                 return None
+
+    def check_and_update_hash_and_deps(self, bn):
+        # Get latest computed hash and deps
+        oldhash, deps = self.srcmd5.get(bn,(None,[]))
+        # read source
+        src = open(os.path.join(self.buildpath, bn)).read()
+        # compute new hash
+        newhash = hashlib.md5(src).hexdigest()
+        # compare
+        match = (oldhash == newhash)
+        if not match:
+            # file have changed
+            # update direct dependencies
+            deps = []
+            for l in src.splitlines():
+                res = includes_re.match(l)
+                if res is not None:
+                    depfn = res.groups()[0]
+                    if os.path.exists(os.path.join(self.buildpath, depfn)):
+                        #print bn + " depends on "+depfn
+                        deps.append(depfn)
+            # store that hashand deps
+            self.srcmd5[bn] = (newhash, deps)
+        # recurse through deps
+        # TODO detect cicular deps.
+        return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match)
                 
-    
     def build(self):
         # Retrieve toolchain user parameters
         toolchain_params = self.PuginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"]
@@ -52,56 +80,70 @@
             else:
                 self.logger.write("PLC :\n")
                 
+            relink = False
             for CFile, CFLAGS in CFilesAndCFLAGS:
                 bn = os.path.basename(CFile)
                 obn = os.path.splitext(bn)[0]+".o"
+                objectfilename = os.path.splitext(CFile)[0]+".o"
+
+                match = self.check_and_update_hash_and_deps(bn)
+                
+                if match:
+                    self.logger.write("   [pass]  "+bn+" -> "+obn+"\n")
+                else:
+                    relink = True
+
+                    self.logger.write("   [CC]  "+bn+" -> "+obn+"\n")
+                    
+                    status, result, err_result = ProcessLogger(
+                           self.logger,
+                           "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
+                               (self.compiler, CFile, objectfilename, self._CFLAGS, CFLAGS)
+                           ).spin()
+
+                    if status :
+                        self.logger.write_error("C compilation of "+ bn +" failed.\n")
+                        return False
+
                 obns.append(obn)
-                self.logger.write("   [CC]  "+bn+" -> "+obn+"\n")
-                objectfilename = os.path.splitext(CFile)[0]+".o"
-                
-                status, result, err_result = ProcessLogger(
-                       self.logger,
-                       "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
-                           (self.compiler, CFile, objectfilename, self._CFLAGS, CFLAGS)
-                       ).spin()
-
-                if status :
-                    self.logger.write_error("C compilation of "+ bn +" failed.\n")
-                    return False
                 objs.append(objectfilename)
 
         ######### GENERATE library FILE ########################################
         # Link all the object files into one binary file
         self.logger.write("Linking :\n")
-        objstring = []
-
-        # Generate list .o files
-        listobjstring = '"' + '"  "'.join(objs) + '"'
-
-        ALLldflags = ' '.join(self.CustomLDFLAGS+self.PuginsRootInstance.LDFLAGS+[self._LDFLAGS])
-
-        self.logger.write("   [CC]  " + ' '.join(obns)+" -> " + self.exe + "\n")
-
-        status, result, err_result = ProcessLogger(
-               self.logger,
-               "\"%s\" %s -o \"%s\" %s"%
-                   (self.linker,
-                    listobjstring,
-                    self.exe_path,
-                    ALLldflags)
-               ).spin()
-        
-        if status :
-            return False
-        else :
-            # Calculate md5 key and get data for the new created PLC
-            data=self.GetBinaryCode()
-            self.md5key = hashlib.md5(data).hexdigest()
-
-            # Store new PLC filename based on md5 key
-            file = open(self._GetMD5FileName(), "w")
-            file.write(self.md5key)
-            file.close()
+        if relink:
+            objstring = []
+    
+            # Generate list .o files
+            listobjstring = '"' + '"  "'.join(objs) + '"'
+    
+            ALLldflags = ' '.join(self.CustomLDFLAGS+self.PuginsRootInstance.LDFLAGS+[self._LDFLAGS])
+    
+            self.logger.write("   [CC]  " + ' '.join(obns)+" -> " + self.exe + "\n")
+    
+            status, result, err_result = ProcessLogger(
+                   self.logger,
+                   "\"%s\" %s -o \"%s\" %s"%
+                       (self.linker,
+                        listobjstring,
+                        self.exe_path,
+                        ALLldflags)
+                   ).spin()
+            
+            if status :
+                return False
+            else :
+                # Calculate md5 key and get data for the new created PLC
+                data=self.GetBinaryCode()
+                self.md5key = hashlib.md5(data).hexdigest()
+    
+                # Store new PLC filename based on md5 key
+                f = open(self._GetMD5FileName(), "w")
+                f.write(self.md5key)
+                f.close()
+        else:
+            self.logger.write("   [pass]  " + ' '.join(obns)+" -> " + self.exe + "\n")
+            
         
         return True