etisserant@285: import os, re, operator etisserant@203: from wxPopen import ProcessLogger etisserant@203: import hashlib etisserant@203: etisserant@285: includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*') etisserant@285: etisserant@203: class toolchain_gcc(): etisserant@203: """ etisserant@203: This abstract class contains GCC specific code. etisserant@203: It cannot be used as this and should be inherited in a target specific etisserant@203: class such as target_linux or target_win32 etisserant@203: """ lbessard@323: def __init__(self, PluginsRootInstance): lbessard@323: self.PluginsRootInstance = PluginsRootInstance lbessard@323: self.logger = PluginsRootInstance.logger lbessard@323: self.exe = PluginsRootInstance.GetProjectName() + self.extension lbessard@323: self.buildpath = PluginsRootInstance._getBuildPath() etisserant@203: self.exe_path = os.path.join(self.buildpath, self.exe) etisserant@203: self.md5key = None etisserant@285: self.srcmd5 = {} etisserant@203: etisserant@297: def getBuilderCFLAGS(self): etisserant@290: """ etisserant@290: Returns list of builder specific CFLAGS etisserant@290: """ lbessard@323: return [self.PluginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"].getCFLAGS()] etisserant@290: etisserant@297: def getBuilderLDFLAGS(self): etisserant@290: """ etisserant@290: Returns list of builder specific LDFLAGS etisserant@290: """ lbessard@323: return self.PluginsRootInstance.LDFLAGS + \ lbessard@323: [self.PluginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"].getLDFLAGS()] etisserant@290: etisserant@203: def GetBinaryCode(self): etisserant@203: try: etisserant@203: return open(self.exe_path, "rb").read() etisserant@203: except Exception, e: etisserant@203: return None etisserant@203: etisserant@203: def _GetMD5FileName(self): etisserant@203: return os.path.join(self.buildpath, "lastbuildPLC.md5") etisserant@203: etisserant@203: def GetBinaryCodeMD5(self): etisserant@203: if self.md5key is not None: etisserant@203: return self.md5key etisserant@203: else: etisserant@203: try: etisserant@203: return open(self._GetMD5FileName(), "r").read() etisserant@203: except Exception, e: etisserant@203: return None etisserant@285: etisserant@285: def check_and_update_hash_and_deps(self, bn): etisserant@285: # Get latest computed hash and deps etisserant@285: oldhash, deps = self.srcmd5.get(bn,(None,[])) etisserant@285: # read source etisserant@285: src = open(os.path.join(self.buildpath, bn)).read() etisserant@285: # compute new hash etisserant@285: newhash = hashlib.md5(src).hexdigest() etisserant@285: # compare etisserant@285: match = (oldhash == newhash) etisserant@285: if not match: etisserant@285: # file have changed etisserant@285: # update direct dependencies etisserant@285: deps = [] etisserant@285: for l in src.splitlines(): etisserant@285: res = includes_re.match(l) etisserant@285: if res is not None: etisserant@285: depfn = res.groups()[0] etisserant@285: if os.path.exists(os.path.join(self.buildpath, depfn)): etisserant@285: #print bn + " depends on "+depfn etisserant@285: deps.append(depfn) etisserant@285: # store that hashand deps etisserant@285: self.srcmd5[bn] = (newhash, deps) etisserant@285: # recurse through deps etisserant@285: # TODO detect cicular deps. etisserant@285: return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match) etisserant@203: etisserant@203: def build(self): etisserant@203: # Retrieve toolchain user parameters lbessard@323: toolchain_params = self.PluginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"] etisserant@203: self.compiler = toolchain_params.getCompiler() etisserant@203: self.linker = toolchain_params.getLinker() etisserant@290: etisserant@290: Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) etisserant@203: etisserant@203: ######### GENERATE OBJECT FILES ######################################## etisserant@203: obns = [] etisserant@203: objs = [] lbessard@323: relink = False lbessard@323: for Location, CFilesAndCFLAGS, DoCalls in self.PluginsRootInstance.LocationCFilesAndCFLAGS: etisserant@203: if Location: laurent@361: self.logger.write(_("Plugin : ") + self.PluginsRootInstance.GetChildByIECLocation(Location).GetCurrentName() + " " + str(Location)+"\n") etisserant@203: else: laurent@361: self.logger.write(_("PLC :\n")) etisserant@203: etisserant@203: for CFile, CFLAGS in CFilesAndCFLAGS: etisserant@203: bn = os.path.basename(CFile) etisserant@203: obn = os.path.splitext(bn)[0]+".o" etisserant@285: objectfilename = os.path.splitext(CFile)[0]+".o" etisserant@285: etisserant@285: match = self.check_and_update_hash_and_deps(bn) etisserant@285: etisserant@285: if match: etisserant@285: self.logger.write(" [pass] "+bn+" -> "+obn+"\n") etisserant@285: else: etisserant@285: relink = True etisserant@285: etisserant@285: self.logger.write(" [CC] "+bn+" -> "+obn+"\n") etisserant@285: etisserant@285: status, result, err_result = ProcessLogger( etisserant@285: self.logger, etisserant@285: "\"%s\" -c \"%s\" -o \"%s\" %s %s"% etisserant@290: (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS) etisserant@285: ).spin() etisserant@285: etisserant@285: if status : lbessard@323: self.srcmd5.pop(bn) laurent@361: self.logger.write_error(_("C compilation of %s failed.\n")%bn) etisserant@285: return False etisserant@285: etisserant@203: obns.append(obn) etisserant@203: objs.append(objectfilename) etisserant@203: etisserant@203: ######### GENERATE library FILE ######################################## etisserant@203: # Link all the object files into one binary file laurent@361: self.logger.write(_("Linking :\n")) etisserant@285: if relink: etisserant@285: objstring = [] etisserant@285: etisserant@285: # Generate list .o files etisserant@285: listobjstring = '"' + '" "'.join(objs) + '"' etisserant@285: etisserant@290: ALLldflags = ' '.join(self.getBuilderLDFLAGS()) etisserant@285: etisserant@285: self.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n") etisserant@285: etisserant@285: status, result, err_result = ProcessLogger( etisserant@285: self.logger, etisserant@285: "\"%s\" %s -o \"%s\" %s"% etisserant@285: (self.linker, etisserant@285: listobjstring, etisserant@285: self.exe_path, etisserant@285: ALLldflags) etisserant@285: ).spin() etisserant@285: etisserant@285: if status : etisserant@285: return False etisserant@285: else : etisserant@285: # Calculate md5 key and get data for the new created PLC etisserant@285: data=self.GetBinaryCode() etisserant@285: self.md5key = hashlib.md5(data).hexdigest() etisserant@285: etisserant@285: # Store new PLC filename based on md5 key etisserant@285: f = open(self._GetMD5FileName(), "w") etisserant@285: f.write(self.md5key) etisserant@285: f.close() etisserant@285: else: etisserant@285: self.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") etisserant@285: etisserant@203: etisserant@203: return True etisserant@203: