targets/toolchain_gcc.py
changeset 1784 64beb9e9c749
parent 1777 c46ec818bdd7
child 1831 56b48961cc68
equal deleted inserted replaced
1729:31e63e25b4cc 1784:64beb9e9c749
    21 #
    21 #
    22 # You should have received a copy of the GNU General Public License
    22 # You should have received a copy of the GNU General Public License
    23 # along with this program; if not, write to the Free Software
    23 # along with this program; if not, write to the Free Software
    24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    25 
    25 
    26 import os, re, operator
    26 import os
       
    27 import re
       
    28 import operator
    27 from util.ProcessLogger import ProcessLogger
    29 from util.ProcessLogger import ProcessLogger
    28 import hashlib
    30 import hashlib
    29 
    31 
    30 includes_re =  re.compile('\s*#include\s*["<]([^">]*)[">].*')
    32 includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
       
    33 
    31 
    34 
    32 class toolchain_gcc():
    35 class toolchain_gcc():
    33     """
    36     """
    34     This abstract class contains GCC specific code.
    37     This abstract class contains GCC specific code.
    35     It cannot be used as this and should be inherited in a target specific
    38     It cannot be used as this and should be inherited in a target specific
    37     """
    40     """
    38     def __init__(self, CTRInstance):
    41     def __init__(self, CTRInstance):
    39         self.CTRInstance = CTRInstance
    42         self.CTRInstance = CTRInstance
    40         self.buildpath = None
    43         self.buildpath = None
    41         self.SetBuildPath(self.CTRInstance._getBuildPath())
    44         self.SetBuildPath(self.CTRInstance._getBuildPath())
    42     
    45 
    43     def getBuilderCFLAGS(self):
    46     def getBuilderCFLAGS(self):
    44         """
    47         """
    45         Returns list of builder specific CFLAGS
    48         Returns list of builder specific CFLAGS
    46         """
    49         """
    47         return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()]
    50         return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()]
    49     def getBuilderLDFLAGS(self):
    52     def getBuilderLDFLAGS(self):
    50         """
    53         """
    51         Returns list of builder specific LDFLAGS
    54         Returns list of builder specific LDFLAGS
    52         """
    55         """
    53         return self.CTRInstance.LDFLAGS + \
    56         return self.CTRInstance.LDFLAGS + \
    54                [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()]
    57             [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()]
    55 
    58 
    56     def getCompiler(self):
    59     def getCompiler(self):
    57         """
    60         """
    58         Returns compiler
    61         Returns compiler
    59         """
    62         """
    60         return self.CTRInstance.GetTarget().getcontent().getCompiler()
    63         return self.CTRInstance.GetTarget().getcontent().getCompiler()
    61       
    64 
    62     def getLinker(self):
    65     def getLinker(self):
    63         """
    66         """
    64         Returns linker
    67         Returns linker
    65         """
    68         """
    66         return self.CTRInstance.GetTarget().getcontent().getLinker()
    69         return self.CTRInstance.GetTarget().getcontent().getLinker()
    67                
    70 
    68     def GetBinaryCode(self):
    71     def GetBinaryCode(self):
    69         try:
    72         try:
    70             return open(self.exe_path, "rb").read()
    73             return open(self.exe_path, "rb").read()
    71         except Exception, e:
    74         except Exception, e:
    72             return None
    75             return None
    73         
    76 
    74     def _GetMD5FileName(self):
    77     def _GetMD5FileName(self):
    75         return os.path.join(self.buildpath, "lastbuildPLC.md5")
    78         return os.path.join(self.buildpath, "lastbuildPLC.md5")
    76 
    79 
    77     def ResetBinaryCodeMD5(self):
    80     def ResetBinaryCodeMD5(self):
    78         self.md5key = None
    81         self.md5key = None
    79         try:
    82         try:
    80             os.remove(self._GetMD5FileName())
    83             os.remove(self._GetMD5FileName())
    81         except Exception, e:
    84         except Exception, e:
    82             pass
    85             pass
    83     
    86 
    84     def GetBinaryCodeMD5(self):
    87     def GetBinaryCodeMD5(self):
    85         if self.md5key is not None:
    88         if self.md5key is not None:
    86             return self.md5key
    89             return self.md5key
    87         else:
    90         else:
    88             try:
    91             try:
    89                 return open(self._GetMD5FileName(), "r").read()
    92                 return open(self._GetMD5FileName(), "r").read()
    90             except Exception, e:
    93             except Exception, e:
    91                 return None
    94                 return None
    92     
    95 
    93     def SetBuildPath(self, buildpath):
    96     def SetBuildPath(self, buildpath):
    94         if self.buildpath != buildpath:
    97         if self.buildpath != buildpath:
    95             self.buildpath = buildpath
    98             self.buildpath = buildpath
    96             self.exe = self.CTRInstance.GetProjectName() + self.extension
    99             self.exe = self.CTRInstance.GetProjectName() + self.extension
    97             self.exe_path = os.path.join(self.buildpath, self.exe)
   100             self.exe_path = os.path.join(self.buildpath, self.exe)
    98             self.md5key = None
   101             self.md5key = None
    99             self.srcmd5 = {}
   102             self.srcmd5 = {}
   100             
   103 
   101     def append_cfile_deps(self, src, deps):
   104     def append_cfile_deps(self, src, deps):
   102         for l in src.splitlines():
   105         for l in src.splitlines():
   103             res = includes_re.match(l)
   106             res = includes_re.match(l)
   104             if res is not None:
   107             if res is not None:
   105                 depfn = res.groups()[0]
   108                 depfn = res.groups()[0]
   106                 if os.path.exists(os.path.join(self.buildpath, depfn)):
   109                 if os.path.exists(os.path.join(self.buildpath, depfn)):
   107                     deps.append(depfn)
   110                     deps.append(depfn)
   108                     
   111 
   109     def concat_deps(self, bn):
   112     def concat_deps(self, bn):
   110         # read source
   113         # read source
   111         src = open(os.path.join(self.buildpath, bn),"r").read()
   114         src = open(os.path.join(self.buildpath, bn), "r").read()
   112         # update direct dependencies
   115         # update direct dependencies
   113         deps = []
   116         deps = []
   114         self.append_cfile_deps(src, deps)
   117         self.append_cfile_deps(src, deps)
   115         # recurse through deps
   118         # recurse through deps
   116         # TODO detect cicular deps.
   119         # TODO detect cicular deps.
   117         return reduce(operator.concat, map(self.concat_deps, deps), src)
   120         return reduce(operator.concat, map(self.concat_deps, deps), src)
   118         
   121 
   119     def check_and_update_hash_and_deps(self, bn):
   122     def check_and_update_hash_and_deps(self, bn):
   120         # Get latest computed hash and deps
   123         # Get latest computed hash and deps
   121         oldhash, deps = self.srcmd5.get(bn,(None,[]))
   124         oldhash, deps = self.srcmd5.get(bn, (None, []))
   122         # read source
   125         # read source
   123         src = open(os.path.join(self.buildpath, bn)).read()
   126         src = open(os.path.join(self.buildpath, bn)).read()
   124         # compute new hash
   127         # compute new hash
   125         newhash = hashlib.md5(src).hexdigest()
   128         newhash = hashlib.md5(src).hexdigest()
   126         # compare
   129         # compare
   133             # store that hashand deps
   136             # store that hashand deps
   134             self.srcmd5[bn] = (newhash, deps)
   137             self.srcmd5[bn] = (newhash, deps)
   135         # recurse through deps
   138         # recurse through deps
   136         # TODO detect cicular deps.
   139         # TODO detect cicular deps.
   137         return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match)
   140         return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match)
   138         
   141 
   139     def calc_source_md5(self):
   142     def calc_source_md5(self):
   140         wholesrcdata = ""
   143         wholesrcdata = ""
   141         for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
   144         for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
   142             # Get CFiles list to give it to makefile
   145             # Get CFiles list to give it to makefile
   143             for CFile, CFLAGS in CFilesAndCFLAGS:
   146             for CFile, CFLAGS in CFilesAndCFLAGS:
   144                 CFileName = os.path.basename(CFile)
   147                 CFileName = os.path.basename(CFile)
   145                 wholesrcdata += self.concat_deps(CFileName)
   148                 wholesrcdata += self.concat_deps(CFileName)
   146         return hashlib.md5(wholesrcdata).hexdigest()
   149         return hashlib.md5(wholesrcdata).hexdigest()
   147     
   150 
   148     def calc_md5(self):
   151     def calc_md5(self):
   149         return hashlib.md5(self.GetBinaryCode()).hexdigest()
   152         return hashlib.md5(self.GetBinaryCode()).hexdigest()
   150     
   153 
   151     def build(self):
   154     def build(self):
   152         # Retrieve compiler and linker
   155         # Retrieve compiler and linker
   153         self.compiler = self.getCompiler()
   156         self.compiler = self.getCompiler()
   154         self.linker = self.getLinker()
   157         self.linker = self.getLinker()
   155 
   158 
   156         Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS())
   159         Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS())
   157 
   160 
   158         ######### GENERATE OBJECT FILES ########################################
   161         # ----------------- GENERATE OBJECT FILES ------------------------
   159         obns = []
   162         obns = []
   160         objs = []
   163         objs = []
   161         relink = self.GetBinaryCode() is None
   164         relink = self.GetBinaryCode() is None
   162         for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
   165         for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
   163             if CFilesAndCFLAGS:
   166             if CFilesAndCFLAGS:
   164                 if Location :
   167                 if Location:
   165                     self.CTRInstance.logger.write(".".join(map(str,Location))+" :\n")
   168                     self.CTRInstance.logger.write(".".join(map(str, Location))+" :\n")
   166                 else:
   169                 else:
   167                     self.CTRInstance.logger.write(_("PLC :\n"))
   170                     self.CTRInstance.logger.write(_("PLC :\n"))
   168                 
   171 
   169             for CFile, CFLAGS in CFilesAndCFLAGS:
   172             for CFile, CFLAGS in CFilesAndCFLAGS:
   170                 if CFile.endswith(".c"):
   173                 if CFile.endswith(".c"):
   171                     bn = os.path.basename(CFile)
   174                     bn = os.path.basename(CFile)
   172                     obn = os.path.splitext(bn)[0]+".o"
   175                     obn = os.path.splitext(bn)[0]+".o"
   173                     objectfilename = os.path.splitext(CFile)[0]+".o"
   176                     objectfilename = os.path.splitext(CFile)[0]+".o"
   174 
   177 
   175                     match = self.check_and_update_hash_and_deps(bn)
   178                     match = self.check_and_update_hash_and_deps(bn)
   176                     
   179 
   177                     if match:
   180                     if match:
   178                         self.CTRInstance.logger.write("   [pass]  "+bn+" -> "+obn+"\n")
   181                         self.CTRInstance.logger.write("   [pass]  "+bn+" -> "+obn+"\n")
   179                     else:
   182                     else:
   180                         relink = True
   183                         relink = True
   181 
   184 
   182                         self.CTRInstance.logger.write("   [CC]  "+bn+" -> "+obn+"\n")
   185                         self.CTRInstance.logger.write("   [CC]  "+bn+" -> "+obn+"\n")
   183                         
   186 
   184                         status, result, err_result = ProcessLogger(
   187                         status, result, err_result = ProcessLogger(
   185                                self.CTRInstance.logger,
   188                             self.CTRInstance.logger,
   186                                "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
   189                             "\"%s\" -c \"%s\" -o \"%s\" %s %s" %
   187                                    (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)
   190                             (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)
   188                                ).spin()
   191                         ).spin()
   189 
   192 
   190                         if status :
   193                         if status:
   191                             self.srcmd5.pop(bn)
   194                             self.srcmd5.pop(bn)
   192                             self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n")%bn)
   195                             self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n") % bn)
   193                             return False
   196                             return False
   194                     obns.append(obn)
   197                     obns.append(obn)
   195                     objs.append(objectfilename)
   198                     objs.append(objectfilename)
   196                 elif CFile.endswith(".o"):
   199                 elif CFile.endswith(".o"):
   197                     obns.append(os.path.basename(CFile))
   200                     obns.append(os.path.basename(CFile))
   198                     objs.append(CFile)
   201                     objs.append(CFile)
   199 
   202 
   200         ######### GENERATE OUTPUT FILE ########################################
   203         # ---------------- GENERATE OUTPUT FILE --------------------------
   201         # Link all the object files into one binary file
   204         # Link all the object files into one binary file
   202         self.CTRInstance.logger.write(_("Linking :\n"))
   205         self.CTRInstance.logger.write(_("Linking :\n"))
   203         if relink:
   206         if relink:
   204             objstring = []
   207             objstring = []
   205     
   208 
   206             # Generate list .o files
   209             # Generate list .o files
   207             listobjstring = '"' + '"  "'.join(objs) + '"'
   210             listobjstring = '"' + '"  "'.join(objs) + '"'
   208     
   211 
   209             ALLldflags = ' '.join(self.getBuilderLDFLAGS())
   212             ALLldflags = ' '.join(self.getBuilderLDFLAGS())
   210     
   213 
   211             self.CTRInstance.logger.write("   [CC]  " + ' '.join(obns)+" -> " + self.exe + "\n")
   214             self.CTRInstance.logger.write("   [CC]  " + ' '.join(obns)+" -> " + self.exe + "\n")
   212     
   215 
   213             status, result, err_result = ProcessLogger(
   216             status, result, err_result = ProcessLogger(
   214                    self.CTRInstance.logger,
   217                 self.CTRInstance.logger,
   215                    "\"%s\" %s -o \"%s\" %s"%
   218                 "\"%s\" %s -o \"%s\" %s" %
   216                        (self.linker,
   219                 (self.linker,
   217                         listobjstring,
   220                  listobjstring,
   218                         self.exe_path,
   221                  self.exe_path,
   219                         ALLldflags)
   222                  ALLldflags)
   220                    ).spin()
   223             ).spin()
   221             
   224 
   222             if status :
   225             if status:
   223                 return False
   226                 return False
   224                 
   227 
   225         else:
   228         else:
   226             self.CTRInstance.logger.write("   [pass]  " + ' '.join(obns)+" -> " + self.exe + "\n")
   229             self.CTRInstance.logger.write("   [pass]  " + ' '.join(obns)+" -> " + self.exe + "\n")
   227         
   230 
   228         # Calculate md5 key and get data for the new created PLC
   231         # Calculate md5 key and get data for the new created PLC
   229         self.md5key = self.calc_md5()
   232         self.md5key = self.calc_md5()
   230 
   233 
   231         # Store new PLC filename based on md5 key
   234         # Store new PLC filename based on md5 key
   232         f = open(self._GetMD5FileName(), "w")
   235         f = open(self._GetMD5FileName(), "w")
   233         f.write(self.md5key)
   236         f.write(self.md5key)
   234         f.close()
   237         f.close()
   235         
   238 
   236         return True
   239         return True
   237