diff -r 64d8f52bc8c8 -r 6ebd9c40b2be targets/toolchain_gcc.py --- a/targets/toolchain_gcc.py Mon Aug 14 19:13:01 2017 +0300 +++ b/targets/toolchain_gcc.py Mon Aug 14 21:09:48 2017 +0300 @@ -1,237 +1,237 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is part of Beremiz, a Integrated Development Environment for -# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# Copyright (C) 2017: Paul Beltyukov -# -# See COPYING file for copyrights details. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -import os, re, operator -from util.ProcessLogger import ProcessLogger -import hashlib - -includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*') - -class toolchain_gcc(): - """ - This abstract class contains GCC specific code. - It cannot be used as this and should be inherited in a target specific - class such as target_linux or target_win32 - """ - def __init__(self, CTRInstance): - self.CTRInstance = CTRInstance - self.buildpath = None - self.SetBuildPath(self.CTRInstance._getBuildPath()) - - def getBuilderCFLAGS(self): - """ - Returns list of builder specific CFLAGS - """ - return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()] - - def getBuilderLDFLAGS(self): - """ - Returns list of builder specific LDFLAGS - """ - return self.CTRInstance.LDFLAGS + \ - [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()] - - def getCompiler(self): - """ - Returns compiler - """ - return self.CTRInstance.GetTarget().getcontent().getCompiler() - - def getLinker(self): - """ - Returns linker - """ - return self.CTRInstance.GetTarget().getcontent().getLinker() - - def GetBinaryCode(self): - try: - return open(self.exe_path, "rb").read() - except Exception, e: - return None - - def _GetMD5FileName(self): - return os.path.join(self.buildpath, "lastbuildPLC.md5") - - def ResetBinaryCodeMD5(self): - self.md5key = None - try: - os.remove(self._GetMD5FileName()) - except Exception, e: - pass - - def GetBinaryCodeMD5(self): - if self.md5key is not None: - return self.md5key - else: - try: - return open(self._GetMD5FileName(), "r").read() - except Exception, e: - return None - - def SetBuildPath(self, buildpath): - if self.buildpath != buildpath: - self.buildpath = buildpath - self.exe = self.CTRInstance.GetProjectName() + self.extension - self.exe_path = os.path.join(self.buildpath, self.exe) - self.md5key = None - self.srcmd5 = {} - - def append_cfile_deps(self, src, 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)): - deps.append(depfn) - - def concat_deps(self, bn): - # read source - src = open(os.path.join(self.buildpath, bn),"r").read() - # update direct dependencies - deps = [] - self.append_cfile_deps(src, deps) - # recurse through deps - # TODO detect cicular deps. - return reduce(operator.concat, map(self.concat_deps, deps), src) - - 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 = [] - self.append_cfile_deps(src, deps) - # 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 calc_source_md5(self): - wholesrcdata = "" - for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: - # Get CFiles list to give it to makefile - for CFile, CFLAGS in CFilesAndCFLAGS: - CFileName = os.path.basename(CFile) - wholesrcdata += self.concat_deps(CFileName) - return hashlib.md5(wholesrcdata).hexdigest() - - def calc_md5(self): - return hashlib.md5(self.GetBinaryCode()).hexdigest() - - def build(self): - # Retrieve compiler and linker - self.compiler = self.getCompiler() - self.linker = self.getLinker() - - Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) - - ######### GENERATE OBJECT FILES ######################################## - obns = [] - objs = [] - relink = self.GetBinaryCode() is None - for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: - if CFilesAndCFLAGS: - if Location : - self.CTRInstance.logger.write(".".join(map(str,Location))+" :\n") - else: - self.CTRInstance.logger.write(_("PLC :\n")) - - for CFile, CFLAGS in CFilesAndCFLAGS: - if CFile.endswith(".c"): - 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.CTRInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n") - else: - relink = True - - self.CTRInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n") - - status, result, err_result = ProcessLogger( - self.CTRInstance.logger, - "\"%s\" -c \"%s\" -o \"%s\" %s %s"% - (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS) - ).spin() - - if status : - self.srcmd5.pop(bn) - self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n")%bn) - return False - obns.append(obn) - objs.append(objectfilename) - elif CFile.endswith(".o"): - obns.append(os.path.basename(CFile)) - objs.append(CFile) - - ######### GENERATE OUTPUT FILE ######################################## - # Link all the object files into one binary file - self.CTRInstance.logger.write(_("Linking :\n")) - if relink: - objstring = [] - - # Generate list .o files - listobjstring = '"' + '" "'.join(objs) + '"' - - ALLldflags = ' '.join(self.getBuilderLDFLAGS()) - - self.CTRInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n") - - status, result, err_result = ProcessLogger( - self.CTRInstance.logger, - "\"%s\" %s -o \"%s\" %s"% - (self.linker, - listobjstring, - self.exe_path, - ALLldflags) - ).spin() - - if status : - return False - - else: - self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") - - # Calculate md5 key and get data for the new created PLC - self.md5key = self.calc_md5() - - # Store new PLC filename based on md5 key - f = open(self._GetMD5FileName(), "w") - f.write(self.md5key) - f.close() - - return True - +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of Beremiz, a Integrated Development Environment for +# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# Copyright (C) 2017: Paul Beltyukov +# +# See COPYING file for copyrights details. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import os, re, operator +from util.ProcessLogger import ProcessLogger +import hashlib + +includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*') + +class toolchain_gcc(): + """ + This abstract class contains GCC specific code. + It cannot be used as this and should be inherited in a target specific + class such as target_linux or target_win32 + """ + def __init__(self, CTRInstance): + self.CTRInstance = CTRInstance + self.buildpath = None + self.SetBuildPath(self.CTRInstance._getBuildPath()) + + def getBuilderCFLAGS(self): + """ + Returns list of builder specific CFLAGS + """ + return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()] + + def getBuilderLDFLAGS(self): + """ + Returns list of builder specific LDFLAGS + """ + return self.CTRInstance.LDFLAGS + \ + [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()] + + def getCompiler(self): + """ + Returns compiler + """ + return self.CTRInstance.GetTarget().getcontent().getCompiler() + + def getLinker(self): + """ + Returns linker + """ + return self.CTRInstance.GetTarget().getcontent().getLinker() + + def GetBinaryCode(self): + try: + return open(self.exe_path, "rb").read() + except Exception, e: + return None + + def _GetMD5FileName(self): + return os.path.join(self.buildpath, "lastbuildPLC.md5") + + def ResetBinaryCodeMD5(self): + self.md5key = None + try: + os.remove(self._GetMD5FileName()) + except Exception, e: + pass + + def GetBinaryCodeMD5(self): + if self.md5key is not None: + return self.md5key + else: + try: + return open(self._GetMD5FileName(), "r").read() + except Exception, e: + return None + + def SetBuildPath(self, buildpath): + if self.buildpath != buildpath: + self.buildpath = buildpath + self.exe = self.CTRInstance.GetProjectName() + self.extension + self.exe_path = os.path.join(self.buildpath, self.exe) + self.md5key = None + self.srcmd5 = {} + + def append_cfile_deps(self, src, 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)): + deps.append(depfn) + + def concat_deps(self, bn): + # read source + src = open(os.path.join(self.buildpath, bn),"r").read() + # update direct dependencies + deps = [] + self.append_cfile_deps(src, deps) + # recurse through deps + # TODO detect cicular deps. + return reduce(operator.concat, map(self.concat_deps, deps), src) + + 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 = [] + self.append_cfile_deps(src, deps) + # 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 calc_source_md5(self): + wholesrcdata = "" + for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: + # Get CFiles list to give it to makefile + for CFile, CFLAGS in CFilesAndCFLAGS: + CFileName = os.path.basename(CFile) + wholesrcdata += self.concat_deps(CFileName) + return hashlib.md5(wholesrcdata).hexdigest() + + def calc_md5(self): + return hashlib.md5(self.GetBinaryCode()).hexdigest() + + def build(self): + # Retrieve compiler and linker + self.compiler = self.getCompiler() + self.linker = self.getLinker() + + Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) + + ######### GENERATE OBJECT FILES ######################################## + obns = [] + objs = [] + relink = self.GetBinaryCode() is None + for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: + if CFilesAndCFLAGS: + if Location : + self.CTRInstance.logger.write(".".join(map(str,Location))+" :\n") + else: + self.CTRInstance.logger.write(_("PLC :\n")) + + for CFile, CFLAGS in CFilesAndCFLAGS: + if CFile.endswith(".c"): + 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.CTRInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n") + else: + relink = True + + self.CTRInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n") + + status, result, err_result = ProcessLogger( + self.CTRInstance.logger, + "\"%s\" -c \"%s\" -o \"%s\" %s %s"% + (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS) + ).spin() + + if status : + self.srcmd5.pop(bn) + self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n")%bn) + return False + obns.append(obn) + objs.append(objectfilename) + elif CFile.endswith(".o"): + obns.append(os.path.basename(CFile)) + objs.append(CFile) + + ######### GENERATE OUTPUT FILE ######################################## + # Link all the object files into one binary file + self.CTRInstance.logger.write(_("Linking :\n")) + if relink: + objstring = [] + + # Generate list .o files + listobjstring = '"' + '" "'.join(objs) + '"' + + ALLldflags = ' '.join(self.getBuilderLDFLAGS()) + + self.CTRInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n") + + status, result, err_result = ProcessLogger( + self.CTRInstance.logger, + "\"%s\" %s -o \"%s\" %s"% + (self.linker, + listobjstring, + self.exe_path, + ALLldflags) + ).spin() + + if status : + return False + + else: + self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") + + # Calculate md5 key and get data for the new created PLC + self.md5key = self.calc_md5() + + # Store new PLC filename based on md5 key + f = open(self._GetMD5FileName(), "w") + f.write(self.md5key) + f.close() + + return True +