Organized controller's _Build sub-methods layout. Many (unwanted) white space changes.
authorEdouard Tisserant
Wed, 21 May 2014 18:43:54 +0200
changeset 1407 cf3d2b53dd68
parent 1406 82db84fe88ea
child 1408 eb2aa27602b7
Organized controller's _Build sub-methods layout. Many (unwanted) white space changes.
ProjectController.py
util/ProcessLogger.py
--- a/ProjectController.py	Tue May 13 00:43:06 2014 +0200
+++ b/ProjectController.py	Wed May 21 18:43:54 2014 +0200
@@ -1,5 +1,5 @@
 """
-Beremiz Project Controller 
+Beremiz Project Controller
 """
 import os,sys,traceback
 import time
@@ -63,14 +63,14 @@
 
 class ProjectController(ConfigTreeNode, PLCControler):
     """
-    This class define Root object of the confnode tree. 
+    This class define Root object of the confnode tree.
     It is responsible of :
     - Managing project directory
     - Building project
     - Handling PLCOpenEditor controler and view
     - Loading user confnodes and instanciante them as children
     - ...
-    
+
     """
 
     # For root object, available Children Types are modules of the confnode packages.
@@ -92,7 +92,7 @@
               <xsd:complexType>
               """+"\n".join(['<xsd:attribute name='+
                              '"Enable_'+ libname + '_Library" '+
-                             'type="xsd:boolean" use="optional" default="true"/>' 
+                             'type="xsd:boolean" use="optional" default="true"/>'
                              for libname,lib in features.libraries])+"""
               </xsd:complexType>""") if len(features.libraries)>0 else '<xsd:complexType/>') + """
             </xsd:element>
@@ -104,7 +104,7 @@
     </xsd:schema>
     """
     EditorType = ProjectNodeEditor
-    
+
     def __init__(self, frame, logger):
         PLCControler.__init__(self)
 
@@ -115,10 +115,10 @@
         self.DebugValuesBuffers = []
         self.DebugTicks = []
         self.SetAppFrame(frame, logger)
-        
+
         self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else ""))
         self.ieclib_path = os.path.join(base_folder, "matiec", "lib")
-        
+
         # Setup debug information
         self.IECdebug_datas = {}
         self.IECdebug_lock = Lock()
@@ -147,7 +147,7 @@
         if self.DebugTimer:
             self.DebugTimer.cancel()
         self.KillDebugThread()
-    
+
     def LoadLibraries(self):
         self.Libraries = []
         TypeStack=[]
@@ -156,7 +156,7 @@
                 Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
                 TypeStack.append(Lib.GetTypes())
                 self.Libraries.append(Lib)
-    
+
     def SetAppFrame(self, frame, logger):
         self.AppFrame = frame
         self.logger = logger
@@ -164,23 +164,23 @@
         if self.DispatchDebugValuesTimer is not None:
             self.DispatchDebugValuesTimer.Stop()
         self.DispatchDebugValuesTimer = None
-        
+
         if frame is not None:
-            
+
             # Timer to pull PLC status
             self.StatusTimer = wx.Timer(self.AppFrame, -1)
-            self.AppFrame.Bind(wx.EVT_TIMER, 
+            self.AppFrame.Bind(wx.EVT_TIMER,
                 self.PullPLCStatusProc, self.StatusTimer)
 
             if self._connector is not None:
                 frame.LogViewer.SetLogSource(self._connector)
                 self.StatusTimer.Start(milliseconds=500, oneShot=False)
-            
+
             # Timer to dispatch debug values to consumers
             self.DispatchDebugValuesTimer = wx.Timer(self.AppFrame, -1)
-            self.AppFrame.Bind(wx.EVT_TIMER, 
+            self.AppFrame.Bind(wx.EVT_TIMER,
                 self.DispatchDebugValuesProc, self.DispatchDebugValuesTimer)
-            
+
             self.RefreshConfNodesBlockLists()
 
     def ResetAppFrame(self, logger):
@@ -188,7 +188,7 @@
             self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer)
             self.StatusTimer = None
             self.AppFrame = None
-        
+
         self.logger = logger
 
     def CTNName(self):
@@ -205,16 +205,16 @@
 
     def GetIECLibPath(self):
         return self.ieclib_path
-    
+
     def GetIEC2cPath(self):
         return self.iec2c_path
-    
+
     def GetCurrentLocation(self):
         return ()
 
     def GetCurrentName(self):
         return ""
-    
+
     def _GetCurrentName(self):
         return ""
 
@@ -223,10 +223,10 @@
 
     def GetProjectName(self):
         return os.path.split(self.ProjectPath)[1]
-    
+
     def GetIconName(self):
         return "PROJECT"
-    
+
     def GetDefaultTargetName(self):
         if wx.Platform == '__WXMSW__':
             return "Win32"
@@ -242,15 +242,15 @@
             target_name = self.GetDefaultTargetName()
             target.setcontent(self.Parser.CreateElement(target_name, "TargetType"))
         return target
-    
+
     def GetParamsAttributes(self, path = None):
         params = ConfigTreeNode.GetParamsAttributes(self, path)
         if params[0]["name"] == "BeremizRoot":
             for child in params[0]["children"]:
                 if child["name"] == "TargetType" and child["value"] == '':
-                    child.update(self.GetTarget().getElementInfos("TargetType")) 
+                    child.update(self.GetTarget().getElementInfos("TargetType"))
         return params
-        
+
     def SetParamsAttribute(self, path, value):
         if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None:
             self.BeremizRoot.setTargetType(self.GetTarget())
@@ -258,15 +258,15 @@
         if path.startswith("BeremizRoot.Libraries."):
             wx.CallAfter(self.RefreshConfNodesBlockLists)
         return res
-        
+
     # helper func to check project path write permission
     def CheckProjectPathPerm(self, dosave=True):
         if CheckPathPerm(self.ProjectPath):
             return True
         if self.AppFrame is not None:
-            dialog = wx.MessageDialog(self.AppFrame, 
+            dialog = wx.MessageDialog(self.AppFrame,
                         _('You must have permission to work on the project\nWork on a project copy ?'),
-                        _('Error'), 
+                        _('Error'),
                         wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
             answer = dialog.ShowModal()
             dialog.Destroy()
@@ -277,7 +277,7 @@
                     self.AppFrame.RefreshPageTitles()
                     return True
         return False
-    
+
     def _getProjectFilesPath(self, project_path=None):
         if project_path is not None:
             return os.path.join(project_path, "project_files")
@@ -285,7 +285,7 @@
         if not os.path.exists(projectfiles_path):
             os.mkdir(projectfiles_path)
         return projectfiles_path
-    
+
     def AddProjectDefaultConfiguration(self, config_name="config", res_name="resource1"):
         self.ProjectAddConfiguration(config_name)
         self.ProjectAddConfigurationResource(config_name, res_name)
@@ -299,7 +299,7 @@
         # Verify that chosen folder is empty
         if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
             return _("Chosen folder isn't empty. You can't use it for a new project!")
-        
+
         # Create PLCOpen program
         self.CreateNewProject(
             {"projectName": _("Unnamed"),
@@ -308,7 +308,7 @@
              "companyName": _("Unknown"),
              "creationDateTime": datetime(*localtime()[:6])})
         self.AddProjectDefaultConfiguration()
-        
+
         # Change XSD into class members
         self._AddParamsMembers()
         self.Children = {}
@@ -320,7 +320,7 @@
         # this will create files base XML files
         self.SaveProject()
         return None
-        
+
     def LoadProject(self, ProjectPath, BuildPath=None):
         """
         Load a project contained in a folder
@@ -357,30 +357,30 @@
             #Load and init all the children
             self.LoadChildren()
         self.RefreshConfNodesBlockLists()
-        
+
         if os.path.exists(self._getBuildPath()):
             self.EnableMethod("_Clean", True)
 
         if os.path.isfile(self._getIECcodepath()):
             self.ShowMethod("_showIECcode", True)
-        
+
         self.UpdateMethodsFromPLCStatus()
-        
+
         return None
-    
+
     def RecursiveConfNodeInfos(self, confnode):
         values = []
         for CTNChild in confnode.IECSortedChildren():
             values.append(
                 {"name": "%s: %s" % (CTNChild.GetFullIEC_Channel(),
-                                     CTNChild.CTNName()), 
+                                     CTNChild.CTNName()),
                  "tagname": CTNChild.CTNFullName(),
-                 "type": ITEM_CONFNODE, 
+                 "type": ITEM_CONFNODE,
                  "confnode": CTNChild,
                  "icon": CTNChild.GetIconName(),
                  "values": self.RecursiveConfNodeInfos(CTNChild)})
         return values
-    
+
     def GetProjectInfos(self):
         infos = PLCControler.GetProjectInfos(self)
         configurations = infos["values"].pop(-1)
@@ -394,23 +394,23 @@
             infos["values"].append(resources)
         infos["values"].extend(self.RecursiveConfNodeInfos(self))
         return infos
-    
+
     def CloseProject(self):
         self.ClearChildren()
         self.ResetAppFrame(None)
-        
+
     def SaveProject(self, from_project_path=None):
         if self.CheckProjectPathPerm(False):
             if from_project_path is not None:
                 old_projectfiles_path = self._getProjectFilesPath(from_project_path)
                 if os.path.isdir(old_projectfiles_path):
-                    shutil.copytree(old_projectfiles_path, 
+                    shutil.copytree(old_projectfiles_path,
                                     self._getProjectFilesPath(self.ProjectPath))
             self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
             result = self.CTNRequestSave(from_project_path)
             if result:
                 self.logger.write_error(result)
-    
+
     def SaveProjectAs(self):
         # Ask user to choose a path with write permissions
         if wx.Platform == '__WXMSW__':
@@ -444,12 +444,12 @@
         LocatedCCodeAndFlags=[]
         Extras=[]
         for lib in self.Libraries:
-            res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)  
+            res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)
             LocatedCCodeAndFlags.append(res[:2])
             if len(res)>2:
                 Extras.extend(res[2:])
         return map(list,zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
-    
+
     # Update PLCOpenEditor ConfNode Block types from loaded confnodes
     def RefreshConfNodesBlockLists(self):
         if getattr(self, "Children", None) is not None:
@@ -458,7 +458,7 @@
         if self.AppFrame is not None:
             self.AppFrame.RefreshLibraryPanel()
             self.AppFrame.RefreshEditor()
-    
+
     # Update a PLCOpenEditor Pou variable location
     def UpdateProjectVariableLocation(self, old_leading, new_leading):
         self.Project.updateElementAddress(old_leading, new_leading)
@@ -469,13 +469,13 @@
             self.AppFrame.RefreshFileMenu()
             self.AppFrame.RefreshEditMenu()
             wx.CallAfter(self.AppFrame.RefreshEditor)
-    
+
     def GetVariableLocationTree(self):
         '''
         This function is meant to be overridden by confnodes.
 
         It should returns an list of dictionaries
-        
+
         - IEC_type is an IEC type like BOOL/BYTE/SINT/...
         - location is a string of this variable's location, like "%IX0.0.0"
         '''
@@ -483,13 +483,13 @@
         for child in self.IECSortedChildren():
             children.append(child.GetVariableLocationTree())
         return children
-    
+
     def ConfNodePath(self):
         return os.path.split(__file__)[0]
-    
+
     def CTNPath(self, CTNName=None):
         return self.ProjectPath
-    
+
     def ConfNodeXmlFilePath(self, CTNName=None):
         return os.path.join(self.CTNPath(CTNName), "beremiz.xml")
 
@@ -515,26 +515,26 @@
         # Create a build path in temp folder
         else:
             self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
-            
+
         if not os.path.exists(self.DefaultBuildPath):
             os.makedirs(self.DefaultBuildPath)
         return self.DefaultBuildPath
-    
+
     def _getExtraFilesPath(self):
         return os.path.join(self._getBuildPath(), "extra_files")
 
     def _getIECcodepath(self):
         # define name for IEC code file
         return os.path.join(self._getBuildPath(), "plc.st")
-    
+
     def _getIECgeneratedcodepath(self):
         # define name for IEC generated code file
         return os.path.join(self._getBuildPath(), "generated_plc.st")
-    
+
     def _getIECrawcodepath(self):
         # define name for IEC raw code file
         return os.path.join(self.CTNPath(), "raw_plc.st")
-    
+
     def GetLocations(self):
         locations = []
         filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
@@ -546,24 +546,29 @@
             # This regular expression parses the lines genereated by IEC2C
             LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
             for line in lines:
-                # If line match RE, 
+                # If line match RE,
                 result = LOCATED_MODEL.match(line)
                 if result:
                     # Get the resulting dict
                     resdict = result.groupdict()
                     # rewrite string for variadic location as a tuple of integers
                     resdict['LOC'] = tuple(map(int,resdict['LOC'].split(',')))
-                    # set located size to 'X' if not given 
+                    # set located size to 'X' if not given
                     if not resdict['SIZE']:
                         resdict['SIZE'] = 'X'
                     # finally store into located variable list
                     locations.append(resdict)
         return locations
-    
+
     def GetConfNodeGlobalInstances(self):
         return self._GlobalInstances()
-    
+
     def _Generate_SoftPLC(self):
+        if self._Generate_PLC_ST():
+            return self._Compile_ST_to_SoftPLC()
+        return False
+
+    def _Generate_PLC_ST(self):
         """
         Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C
         @param buildpath: path where files should be created
@@ -571,9 +576,8 @@
 
         # Update PLCOpenEditor ConfNode Block types before generate ST code
         self.RefreshConfNodesBlockLists()
-        
+
         self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"))
-        buildpath = self._getBuildPath()
         # ask PLCOpenEditor controller to write ST/IL/SFC code file
         program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath())
         if len(warnings) > 0:
@@ -599,22 +603,25 @@
         plc_file = open(self._getIECcodepath(), "a")
         plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
         plc_file.close()
-
+        return True
+
+    def _Compile_ST_to_SoftPLC(self):
         self.logger.write(_("Compiling IEC Program into C code...\n"))
+        buildpath = self._getBuildPath()
 
         # Now compile IEC code into many C files
-        # files are listed to stdout, and errors to stderr. 
+        # files are listed to stdout, and errors to stderr.
         status, result, err_result = ProcessLogger(
                self.logger,
                "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%(
                          self.iec2c_path,
-                         self.ieclib_path, 
+                         self.ieclib_path,
                          buildpath,
                          self._getIECcodepath()),
                no_stdout=True, no_stderr=True).spin()
         if status:
             # Failed !
-            
+
             # parse iec2c's error message. if it contains a line number,
             # then print those lines from the generated IEC file.
             for err_line in err_result.split('\n'):
@@ -624,7 +631,7 @@
                 if m_result is not None:
                     first_line, first_column, last_line, last_column, error = m_result.groups()
                     first_line, last_line = int(first_line), int(last_line)
-                    
+
                     last_section = None
                     f = open(self._getIECcodepath())
 
@@ -640,10 +647,10 @@
                             self.logger.write_warning("%04d: %s" % (i, line))
 
                     f.close()
-            
+
             self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status)
             return False
-        
+
         # Now extract C files of stdout
         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
         # remove those that are not to be compiled because included by others
@@ -679,7 +686,7 @@
         targetname = self.GetTarget().getcontent().getLocalTag()
         targetclass = targets.GetBuilder(targetname)
 
-        # if target already 
+        # if target already
         if self._builder is None or not isinstance(self._builder,targetclass):
             # Get classname instance
             self._builder = targetclass(self)
@@ -703,20 +710,20 @@
     #                C CODE GENERATION METHODS
     #
     #######################################################################
-    
+
     def CTNGenerate_C(self, buildpath, locations):
         """
-        Return C code generated by iec2c compiler 
+        Return C code generated by iec2c compiler
         when _generate_softPLC have been called
         @param locations: ignored
         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
         """
 
-        return ([(C_file_name, self.plcCFLAGS) 
-                for C_file_name in self.PLCGeneratedCFiles ], 
+        return ([(C_file_name, self.plcCFLAGS)
+                for C_file_name in self.PLCGeneratedCFiles ],
                "", # no ldflags
                False) # do not expose retreive/publish calls
-    
+
     def ResetIECProgramsAndVariables(self):
         """
         Reset variable and program list that are parsed from
@@ -743,7 +750,7 @@
                 self._ProgramList = []
                 self._VariablesList = []
                 self._IECPathToIdx = {}
-                
+
                 # Separate sections
                 ListGroup = []
                 for line in open(csvfile,'r').xreadlines():
@@ -754,7 +761,7 @@
                     elif len(strippedline) > 0 and len(ListGroup) > 0:
                         # append to this section
                         ListGroup[-1].append(strippedline)
-        
+
                 # first section contains programs
                 for line in ListGroup[0]:
                     # Split and Maps each field to dictionnary entries
@@ -763,7 +770,7 @@
                     attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
                     # Push this dictionnary into result.
                     self._ProgramList.append(attrs)
-        
+
                 # second section contains all variables
                 config_FBs = {}
                 for line in ListGroup[1]:
@@ -776,7 +783,7 @@
                         if config_FB:
                             parts = [config_FB] + parts[2:]
                             attrs["C_path"] = '.'.join(parts)
-                        else: 
+                        else:
                             attrs["C_path"] = '__'.join(parts[1:])
                     else:
                         attrs["C_path"] = '__'.join(parts)
@@ -788,11 +795,11 @@
                     IEC_path=attrs["IEC_path"]
                     Idx=int(attrs["num"])
                     self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
-                
+
                 # third section contains ticktime
                 if len(ListGroup) > 2:
-                    self._Ticktime = int(ListGroup[2][0]) 
-                
+                    self._Ticktime = int(ListGroup[2][0])
+
             except Exception,e:
                 self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
                 self.logger.write_error(traceback.format_exc())
@@ -818,7 +825,7 @@
                "MEM":"extern __IEC_%(type)s_p %(C_path)s;",
                "OUT":"extern __IEC_%(type)s_p %(C_path)s;",
                "VAR":"extern __IEC_%(type)s_t %(C_path)s;",
-               "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v 
+               "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
                for v in self._VariablesList if v["C_path"].find('.')<0]),
            "for_each_variable_do_code":"\n".join([
                {"EXT":"    (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
@@ -836,9 +843,9 @@
                 "OUT":"        return %(type)s_O_ENUM;\n",
                 "VAR":"        return %(type)s_ENUM;\n"}[v["vartype"]]%v
                 for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])}
-        
+
         return debug_code
-        
+
     def Generate_plc_main(self):
         """
         Use confnodes layout given in LocationCFilesAndCFLAGS to
@@ -848,7 +855,7 @@
         # in retreive, publish, init, cleanup
         locstrs = map(lambda x:"_".join(map(str,x)),
            [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
-        
+
         # Generate main, based on template
         if not self.BeremizRoot.getDisable_Extensions():
             plc_main_code = targets.GetCode("plc_main_head") % {
@@ -882,7 +889,7 @@
         plc_main_code += targets.GetCode("plc_main_tail")
         return plc_main_code
 
-        
+
     def _Build(self):
         """
         Method called by user to (re)build SoftPLC and confnode tree
@@ -890,7 +897,7 @@
         if self.AppFrame is not None:
             self.AppFrame.ClearErrors()
         self._CloseView(self._IECCodeView)
-        
+
         buildpath = self._getBuildPath()
 
         # Eventually create build dir
@@ -908,21 +915,52 @@
 
         # If IEC code gen fail, bail out.
         if not IECGenRes:
-            self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
+            self.logger.write_error(_("PLC code generation failed !\n"))
             self.ResetBuildMD5()
             return False
 
         # Reset variable and program list that are parsed from
         # CSV file generated by IEC2C compiler.
         self.ResetIECProgramsAndVariables()
-        
+
+        # Collect platform specific C code
+        # Code and other files from extension
+        if not self._Generate_runtime():
+            return False
+
+        # Get current or fresh builder
+        builder = self.GetBuilder()
+        if builder is None:
+            self.logger.write_error(_("Fatal : cannot get builder.\n"))
+            self.ResetBuildMD5()
+            return False
+
+        # Build
+        try:
+            if not builder.build() :
+                self.logger.write_error(_("C Build failed.\n"))
+                return False
+        except Exception, exc:
+            self.logger.write_error(_("C Build crashed !\n"))
+            self.logger.write_error(traceback.format_exc())
+            self.ResetBuildMD5()
+            return False
+
+        self.logger.write(_("Successfully built.\n"))
+        # Update GUI status about need for transfer
+        self.CompareLocalAndRemotePLC()
+        return True
+
+    def _Generate_runtime(self):
+        buildpath = self._getBuildPath()
+
         # Generate C code and compilation params from confnode hierarchy
         try:
             CTNLocationCFilesAndCFLAGS, CTNLDFLAGS, CTNExtraFiles = self._Generate_C(
-                buildpath, 
+                buildpath,
                 self.PLCGeneratedLocatedVars)
         except Exception, exc:
-            self.logger.write_error(_("Runtime extensions C code generation failed !\n"))
+            self.logger.write_error(_("Runtime IO extensions C code generation failed !\n"))
             self.logger.write_error(traceback.format_exc())
             self.ResetBuildMD5()
             return False
@@ -931,7 +969,7 @@
         try:
             LibCFilesAndCFLAGS, LibLDFLAGS, LibExtraFiles = self.GetLibrariesCCode(buildpath)
         except Exception, exc:
-            self.logger.write_error(_("Runtime extensions C code generation failed !\n"))
+            self.logger.write_error(_("Runtime library extensions C code generation failed !\n"))
             self.logger.write_error(traceback.format_exc())
             self.ResetBuildMD5()
             return False
@@ -939,7 +977,7 @@
         self.LocationCFilesAndCFLAGS =  CTNLocationCFilesAndCFLAGS + LibCFilesAndCFLAGS
         self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
         ExtraFiles = CTNExtraFiles + LibExtraFiles
-        
+
         # Get temporary directory path
         extrafilespath = self._getExtraFilesPath()
         # Remove old directory
@@ -953,7 +991,7 @@
             open(fpath, "wb").write(fobject.read())
         # Now we can forget ExtraFiles (will close files object)
         del ExtraFiles
-        
+
         # Header file for extensions
         open(os.path.join(buildpath,"beremiz.h"), "w").write(targets.GetHeader())
 
@@ -978,32 +1016,9 @@
                 self.logger.write_error(traceback.format_exc())
                 self.ResetBuildMD5()
                 return False
-
         self.logger.write(_("C code generated successfully.\n"))
-
-        # Get current or fresh builder
-        builder = self.GetBuilder()
-        if builder is None:
-            self.logger.write_error(_("Fatal : cannot get builder.\n"))
-            self.ResetBuildMD5()
-            return False
-
-        # Build
-        try:
-            if not builder.build() :
-                self.logger.write_error(_("C Build failed.\n"))
-                return False
-        except Exception, exc:
-            self.logger.write_error(_("C Build crashed !\n"))
-            self.logger.write_error(traceback.format_exc())
-            self.ResetBuildMD5()
-            return False
-
-        self.logger.write(_("Successfully built.\n"))
-        # Update GUI status about need for transfer
-        self.CompareLocalAndRemotePLC()
         return True
-    
+
     def ShowError(self, logger, from_location, to_location):
         chunk_infos = self.GetChunkInfos(from_location, to_location)
         for infos, (start_row, start_col) in chunk_infos:
@@ -1011,7 +1026,7 @@
             end = (to_location[0] - start_row, to_location[1] - start_col)
             if self.AppFrame is not None:
                 self.AppFrame.ShowError(infos, start, end)
-    
+
     _IECCodeView = None
     def _showIECcode(self):
         self._OpenView("IEC code")
@@ -1019,20 +1034,20 @@
     _IECRawCodeView = None
     def _editIECrawcode(self):
         self._OpenView("IEC raw code")
-    
+
     _ProjectFilesView = None
     def _OpenProjectFiles(self):
         self._OpenView("Project Files")
-    
+
     _FileEditors = {}
     def _OpenFileEditor(self, filepath):
         self._OpenView(filepath)
-    
+
     def _OpenView(self, name=None, onlyopened=False):
         if name == "IEC code":
             if self._IECCodeView is None:
                 plc_file = self._getIECcodepath()
-            
+
                 self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name)
                 self._IECCodeView.SetTextSyntax("ALL")
                 self._IECCodeView.SetKeywords(IEC_KEYWORDS)
@@ -1043,78 +1058,78 @@
                 self._IECCodeView.SetText(text = text)
                 self._IECCodeView.SetIcon(GetBitmap("ST"))
                 setattr(self._IECCodeView, "_OnClose", self.OnCloseEditor)
-            
+
             if self._IECCodeView is not None:
                 self.AppFrame.EditProjectElement(self._IECCodeView, name)
-            
+
             return self._IECCodeView
-        
+
         elif name == "IEC raw code":
             if self._IECRawCodeView is None:
                 controler = MiniTextControler(self._getIECrawcodepath(), self)
-                
+
                 self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name)
                 self._IECRawCodeView.SetTextSyntax("ALL")
                 self._IECRawCodeView.SetKeywords(IEC_KEYWORDS)
                 self._IECRawCodeView.RefreshView()
                 self._IECRawCodeView.SetIcon(GetBitmap("ST"))
                 setattr(self._IECRawCodeView, "_OnClose", self.OnCloseEditor)
-            
+
             if self._IECRawCodeView is not None:
                 self.AppFrame.EditProjectElement(self._IECRawCodeView, name)
-            
+
             return self._IECRawCodeView
-        
+
         elif name == "Project Files":
             if self._ProjectFilesView is None:
                 self._ProjectFilesView = FileManagementPanel(self.AppFrame.TabsOpened, self, name, self._getProjectFilesPath(), True)
-                
+
                 extensions = []
                 for extension, name, editor in features.file_editors:
                     if extension not in extensions:
                         extensions.append(extension)
-                self._ProjectFilesView.SetEditableFileExtensions(extensions) 
-                
+                self._ProjectFilesView.SetEditableFileExtensions(extensions)
+
             if self._ProjectFilesView is not None:
                 self.AppFrame.EditProjectElement(self._ProjectFilesView, name)
-            
+
             return self._ProjectFilesView
-        
+
         elif name is not None and name.find("::") != -1:
             filepath, editor_name = name.split("::")
             if not self._FileEditors.has_key(filepath):
                 if os.path.isfile(filepath):
                     file_extension = os.path.splitext(filepath)[1]
-                        
+
                     editors = dict([(edit_name, edit_class)
                                     for extension, edit_name, edit_class in features.file_editors
                                     if extension == file_extension])
-                    
+
                     if editor_name == "":
                         if len(editors) == 1:
                             editor_name = editors.keys()[0]
                         elif len(editors) > 0:
                             names = editors.keys()
-                            dialog = wx.SingleChoiceDialog(self.AppFrame, 
-                                  _("Select an editor:"), _("Editor selection"), 
+                            dialog = wx.SingleChoiceDialog(self.AppFrame,
+                                  _("Select an editor:"), _("Editor selection"),
                                   names, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
                             if dialog.ShowModal() == wx.ID_OK:
                                 editor_name = names[dialog.GetSelection()]
                             dialog.Destroy()
-                        
+
                     if editor_name != "":
                         name = "::".join([filepath, editor_name])
-                        
+
                         editor = editors[editor_name]()
                         self._FileEditors[filepath] = editor(self.AppFrame.TabsOpened, self, name, self.AppFrame)
                         self._FileEditors[filepath].SetIcon(GetBitmap("FILE"))
                         if isinstance(self._FileEditors[filepath], DebugViewer):
                             self._FileEditors[filepath].SetDataProducer(self)
-            
+
             if self._FileEditors.has_key(filepath):
                 editor = self._FileEditors[filepath]
                 self.AppFrame.EditProjectElement(editor, editor.GetTagName())
-                
+
             return self._FileEditors.get(filepath)
         else:
             return ConfigTreeNode._OpenView(self, self.CTNName(), onlyopened)
@@ -1147,7 +1162,7 @@
         if log_count:
             if self.AppFrame is not None:
                 self.AppFrame.LogViewer.SetLogCounters(log_count)
-    
+
     def UpdateMethodsFromPLCStatus(self):
         status = None
         if self._connector is not None:
@@ -1184,16 +1199,16 @@
                     self.AppFrame.ConnectionStatusBar.SetStatusText(
                         _("Connected to URI: %s") % self.BeremizRoot.getURI_location().strip(), 1)
                     self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2)
-                
+
     def PullPLCStatusProc(self, event):
         self.UpdateMethodsFromPLCStatus()
-        
+
     def SnapshotAndResetDebugValuesBuffers(self):
-        buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers, 
+        buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
             [list() for iec_path in self.TracedIECPath])
         ticks, self.DebugTicks = self.DebugTicks, []
         return ticks, buffers
-    
+
     def RegisterDebugVarToConnector(self):
         self.DebugTimer=None
         Idxs = []
@@ -1208,10 +1223,10 @@
                     # This variable is not needed anymore!
                     IECPathsToPop.append(IECPath)
                 elif IECPath != "__tick__":
-                    # Convert 
+                    # Convert
                     Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
                     if Idx is not None:
-                        if IEC_Type in DebugTypesSize: 
+                        if IEC_Type in DebugTypesSize:
                             Idxs.append((Idx, IEC_Type, fvalue, IECPath))
                         else:
                             self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n")%IEC_Type)
@@ -1229,14 +1244,14 @@
                 self._connector.SetTraceVariablesList([])
             self.SnapshotAndResetDebugValuesBuffers()
             self.IECdebug_lock.release()
-    
+
     def IsPLCStarted(self):
         return self.previous_plcstate == "Started"
-    
+
     def ReArmDebugRegisterTimer(self):
         if self.DebugTimer is not None:
             self.DebugTimer.cancel()
-        
+
         # Prevent to call RegisterDebugVarToConnector when PLC is not started
         # If an output location var is forced it's leads to segmentation fault in runtime
         # Links between PLC located variables and real variables are not ready
@@ -1250,16 +1265,16 @@
     def GetDebugIECVariableType(self, IECPath):
         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
         return IEC_Type
-        
+
     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False, *args, **kwargs):
         """
         Dispatching use a dictionnary linking IEC variable paths
-        to a WeakKeyDictionary linking 
+        to a WeakKeyDictionary linking
         weakly referenced callables to optionnal args
         """
         if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
             return None
-        
+
         self.IECdebug_lock.acquire()
         # If no entry exist, create a new one with a fresh WeakKeyDictionary
         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
@@ -1273,13 +1288,13 @@
             self.IECdebug_datas[IECPath] = IECdebug_data
         else:
             IECdebug_data[4] |= buffer_list
-        
+
         IECdebug_data[0][callableobj]=(buffer_list, args, kwargs)
 
         self.IECdebug_lock.release()
-        
+
         self.ReArmDebugRegisterTimer()
-        
+
         return IECdebug_data[1]
 
     def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
@@ -1292,7 +1307,7 @@
             else:
                 IECdebug_data[4] = reduce(
                     lambda x, y: x|y,
-                    [buffer_list for buffer_list,args,kwargs 
+                    [buffer_list for buffer_list,args,kwargs
                      in IECdebug_data[0].itervalues()],
                     False)
         self.IECdebug_lock.release()
@@ -1309,33 +1324,33 @@
     def ForceDebugIECVariable(self, IECPath, fvalue):
         if not self.IECdebug_datas.has_key(IECPath):
             return
-        
+
         self.IECdebug_lock.acquire()
-        
+
         # If no entry exist, create a new one with a fresh WeakKeyDictionary
         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
         IECdebug_data[2] = "Forced"
         IECdebug_data[3] = fvalue
-        
+
         self.IECdebug_lock.release()
-        
+
         self.ReArmDebugRegisterTimer()
-    
+
     def ReleaseDebugIECVariable(self, IECPath):
         if not self.IECdebug_datas.has_key(IECPath):
             return
-        
+
         self.IECdebug_lock.acquire()
-        
+
         # If no entry exist, create a new one with a fresh WeakKeyDictionary
         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
         IECdebug_data[2] = "Registered"
         IECdebug_data[3] = None
-        
+
         self.IECdebug_lock.release()
-        
+
         self.ReArmDebugRegisterTimer()
-    
+
     def CallWeakcallables(self, IECPath, function_name, *cargs):
         data_tuple = self.IECdebug_datas.get(IECPath, None)
         if data_tuple is not None:
@@ -1415,7 +1430,7 @@
                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
             if len(debug_ticks) > 0:
                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
-        
+
         delay = time.time() - start_time
         next_refresh = max(REFRESH_PERIOD - delay, 0.2 * delay)
         if self.DispatchDebugValuesTimer is not None and self.DebugThread is not None:
@@ -1437,7 +1452,7 @@
         if self.DispatchDebugValuesTimer is not None:
             self.DispatchDebugValuesTimer.Stop()
 
-    def _connect_debug(self): 
+    def _connect_debug(self):
         self.previous_plcstate = None
         if self.AppFrame:
             self.AppFrame.ResetGraphicViewers()
@@ -1448,7 +1463,7 @@
         if self.DebugThread is None:
             self.DebugThread = Thread(target=self.DebugThreadProc)
             self.DebugThread.start()
-    
+
     def _Run(self):
         """
         Start PLC
@@ -1460,7 +1475,7 @@
         else:
             self.logger.write_error(_("Couldn't start PLC !\n"))
         wx.CallAfter(self.UpdateMethodsFromPLCStatus)
-       
+
     def _Stop(self):
         """
         Stop PLC
@@ -1470,7 +1485,7 @@
 
         # debugthread should die on his own
         #self.KillDebugThread()
-        
+
         wx.CallAfter(self.UpdateMethodsFromPLCStatus)
 
     def _SetConnector(self, connector, update_status=True):
@@ -1493,7 +1508,7 @@
         if self._connector is not None:
             self.logger.write_error(_("Already connected. Please disconnect\n"))
             return
-        
+
         # Get connector uri
         uri = self.\
               BeremizRoot.\
@@ -1512,7 +1527,7 @@
                 self.logger.write_error(_("Local service discovery failed!\n"))
                 self.logger.write_error(traceback.format_exc())
                 uri = None
-            
+
             # Nothing choosed or cancel button
             if uri is None or answer == wx.ID_CANCEL:
                 self.logger.write_error(_("Connection canceled!\n"))
@@ -1529,7 +1544,7 @@
                     self.AppFrame.RefreshFileMenu()
                     self.AppFrame.RefreshEditMenu()
                     self.AppFrame.RefreshPageTitles()
-                           
+
         # Get connector from uri
         try:
             self._SetConnector(connectors.ConnectorFactory(uri, self))
@@ -1547,7 +1562,7 @@
             self.ShowMethod("_Transfer", True)
 
             self.CompareLocalAndRemotePLC()
-            
+
             # Init with actual PLC status and print it
             self.UpdateMethodsFromPLCStatus()
             if self.previous_plcstate is not None:
@@ -1556,7 +1571,7 @@
                 status = ""
 
             #self.logger.write(_("PLC is %s\n")%status)
-            
+
             if self.previous_plcstate in ["Started","Stopped"]:
                 if self.DebugAvailable() and self.GetIECProgramsAndVariables():
                     self.logger.write(_("Debugger ready\n"))
@@ -1590,12 +1605,12 @@
 
     def _Disconnect(self):
         self._SetConnector(None)
-        
+
     def _Transfer(self):
-        # Get the last build PLC's 
+        # Get the last build PLC's
         MD5 = self.GetLastBuildMD5()
-        
-        # Check if md5 file is empty : ask user to build PLC 
+
+        # Check if md5 file is empty : ask user to build PLC
         if MD5 is None :
             self.logger.write_error(_("Failed : Must build before transfer.\n"))
             return False
@@ -1609,12 +1624,12 @@
         extrafiles = []
         for extrafilespath in [self._getExtraFilesPath(),
                                self._getProjectFilesPath()]:
-        
+
             extrafiles.extend(
-                     [(name, open(os.path.join(extrafilespath, name), 
+                     [(name, open(os.path.join(extrafilespath, name),
                                   'rb').read()) \
                       for name in os.listdir(extrafilespath)])
-        
+
         # Send PLC on target
         builder = self.GetBuilder()
         if builder is not None:
--- a/util/ProcessLogger.py	Tue May 13 00:43:06 2014 +0200
+++ b/util/ProcessLogger.py	Wed May 21 18:43:54 2014 +0200
@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 
 #This file is part of Beremiz, a Integrated Development Environment for
-#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. 
+#programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
 #
 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
 #
@@ -31,7 +31,7 @@
 if os.name == 'posix':
     from signal import SIGTERM, SIGKILL
 
-    
+
 class outputThread(Thread):
     """
     Thread is used to print the output of a command to the stdout
@@ -66,10 +66,10 @@
                 err = self.retval
             self.finished = True
             self.endcallback(self.Proc.pid, err)
-        
+
 class ProcessLogger:
-    def __init__(self, logger, Command, finish_callback = None, 
-                 no_stdout = False, no_stderr = False, no_gui = True, 
+    def __init__(self, logger, Command, finish_callback = None,
+                 no_stdout = False, no_stderr = False, no_gui = True,
                  timeout = None, outlimit = None, errlimit = None,
                  endlog = None, keyword = None, kill_it = False, cwd = None):
         self.logger = logger
@@ -86,10 +86,10 @@
         else:
             self.Command = Command
             self.Command_str = subprocess.list2cmdline(self.Command)
-        
+
         self.Command = map(lambda x: x.encode(sys.getfilesystemencoding()),
                            self.Command)
-        
+
         self.finish_callback = finish_callback
         self.no_stdout = no_stdout
         self.no_stderr = no_stderr
@@ -105,27 +105,27 @@
         self.kill_it = kill_it
         self.finishsem = Semaphore(0)
         self.endlock = Lock()
-        
+
         popenargs= {
                "cwd":os.getcwd() if cwd is None else cwd,
-               "stdin":subprocess.PIPE, 
-               "stdout":subprocess.PIPE, 
+               "stdin":subprocess.PIPE,
+               "stdout":subprocess.PIPE,
                "stderr":subprocess.PIPE}
-        
+
         if no_gui == True and wx.Platform == '__WXMSW__':
             self.startupinfo = subprocess.STARTUPINFO()
             self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
             popenargs["startupinfo"] = self.startupinfo
         elif wx.Platform == '__WXGTK__':
             popenargs["shell"] = False
-        
+
         self.Proc = subprocess.Popen( self.Command, **popenargs )
 
         self.outt = outputThread(
                       self.Proc,
                       self.Proc.stdout,
                       self.output,
-                      self.finish) 
+                      self.finish)
         self.outt.start()
 
         self.errt = outputThread(
@@ -147,7 +147,7 @@
             self.logger.write(v)
         if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit):
             self.endlog()
-            
+
     def errors(self,v):
         self.errdata.append(v)
         self.errlen += 1
@@ -195,7 +195,7 @@
             if not self.outt.finished and self.kill_it:
                self.kill()
 
-        
+
     def spin(self):
         self.finishsem.acquire()
         return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]