STCCompilerInterface.st
branchjv
changeset 4028 8e7af453d137
parent 4007 95308b6e887e
parent 4023 03113f2bc542
child 4031 671f88158987
--- a/STCCompilerInterface.st	Tue Oct 11 07:03:24 2016 +0200
+++ b/STCCompilerInterface.st	Thu Oct 20 11:08:07 2016 +0100
@@ -53,9 +53,10 @@
     "Return C compiler flags that are always passed to the C compiler
      when a (ST)C file is compiled."
 
-    ^ OperatingSystem getCPUDefine , ' ', OperatingSystem getOSDefine
+    ^ self getCPUDefine , ' ', self getOSDefine
 
     "Created: / 04-12-2015 / 16:41:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 21-10-2016 / 11:24:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
 builtinCIncludeDirectories
@@ -99,6 +100,101 @@
     "Created: / 09-12-2015 / 16:59:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+getCCDefine
+    "return a string which was used to identify the C-Compiler used
+     when STX was compiled, and which should be passed down when compiling methods.
+     For example, when compiled with GNUC, this is '__GNUC__';
+     on windows, this is either '__VISUAL__', '__BORLANDC__' or '__MINGW64__'"
+
+%{  /* NOCONTEXT */
+#ifndef CC_DEFINE
+# ifdef __win32__
+#  if defined( __BORLANDC__ )
+#   define CC_DEFINE    "__BORLANDC__"
+#  else
+#   if defined( __VISUALC__ )
+#    define CC_DEFINE     "__VISUALC__"
+#   else
+#    if defined( __MINGW64__ )
+#     define CC_DEFINE     "__MINGW64__"
+#    else
+#     if defined( __MINGW32__ )
+#      define CC_DEFINE     "__MINGW32__"
+#     else
+#      define CC_DEFINE     "__CC__"
+#     endif
+#    endif
+#   endif
+#  endif
+# else /* not __win32__ */
+#  if defined(__CLANG__) || defined( __clang__ )
+#   define CC_DEFINE     "__CLANG__"
+#  else
+#   ifdef __GNUC__
+#    define CC_DEFINE     "__GNUC__"
+#   else
+#    define CC_DEFINE     "__CC__"
+#   endif
+#  endif
+# endif
+#endif
+    RETURN ( __MKSTRING(CC_DEFINE));
+%}
+    "
+     STCCompilerInterface getCCDefine
+    "
+!
+
+getCPUDefine
+    "return a string which was used to identify this CPU type when STX was
+     compiled, and which should be passed down when compiling methods.
+     For example, on a 386 (and successors), this may be '-D__x86__'; 
+     on a vax, this would be '-D__vax__'.
+          This is normally not of interest to 'normal' users; however, it is passed
+     down to the c-compiler when methods are incrementally compiled to machine code.
+     Do not use this for CPU determination; only to pass on to stc for compilation.
+     (see OperatingSystem getCPUType for this)"
+
+%{  /* NOCONTEXT */
+#   ifndef CPU_DEFINE
+#       define CPU_DEFINE "-DunknownCPU"
+#   endif
+
+    RETURN ( __MKSTRING(CPU_DEFINE));
+%}
+    "
+     STCCompilerInterface getCPUDefine
+    "
+!
+
+getOSDefine
+    "return a string which was used to identify this machine when stx was
+     compiled, and which should be passed down when compiling methods.
+     For example, on linux, this is '-D__linux__'; on osx, it is '-D__osx__'.
+     Do not use this for OS determination; only to pass on to stc for compilation.
+     (see OperatingSystem getOSType for this)"
+
+%{  /* NOCONTEXT */
+
+#ifndef OS_DEFINE
+# ifdef __win32__
+#  define OS_DEFINE "-D__win32__"
+# endif
+
+# ifndef OS_DEFINE
+#  define OS_DEFINE "-DunknownOS"
+# endif
+#endif
+
+    RETURN ( __MKSTRING(OS_DEFINE));
+
+#undef OS_DEFINE
+%}
+    "
+     STCCompilerInterface getOSDefine
+    "
+!
+
 stcPathOf:command 
     "return the path to an stc command, or nil if not found."
 
@@ -270,20 +366,21 @@
     [
         self generateSTSource:aString.
         self setupCompilationCommandArguments.
-        ok := self compileToC.
-        ok ifFalse:[
-            self reportCompilationErrorFor:stcPath.
-        ].
+        ok := self 
+                compileToC_onError:[:errorFile |
+                    self reportCompilationErrorFor:stcPath fromFile:errorFile
+                ].
 
-        parserFlags stcKeepSIntermediate ifTrue:[ self compileToS ].
+        parserFlags stcKeepSIntermediate ifTrue:[ 
+            self compileToS_onError:[:errorFile | ]
+        ].
         "/ now compile to machine code
-        ok := self compileToObj.
-        ok ifFalse:[
-            self reportCompilationErrorFor:ccPath.
-        ].
+        ok := self 
+                compileToObj_onError:[:errorFile |
+                    self reportCompilationErrorFor:ccPath fromFile:errorFile.
+                ].
 
         originator activityNotification:''.
-        OperatingSystem removeFile:'errorOutput'.
 
         "
          if required, make a shared or otherwise loadable object file for it
@@ -470,62 +567,71 @@
 
 !STCCompilerInterface methodsFor:'machine code generation-helpers'!
 
-compileToC
-    "compile st to C using stc"
+compileToC_onError:aBlock
+    "compile st to C using stc.
+     If any error happens, call aBlock passing it the fileName containing diagnostics"
 
-    |command errorStream ok|
+    |command ok errorOutputFile|
 
     command := (self possiblyQuotedPath:stcPath) , ' ' , stcFlags 
+                , ' -E:',(self possiblyQuotedPath:(Filename tempDirectory / 'lastIncrStcErrorOutput') pathName)
                 , ' -defdir=', (self possiblyQuotedPath:cFileName asFilename directory pathName).
     cFileName asFilename suffix ~= 'c' ifTrue:[
         command := command , ' -cSuffix=',cFileName asFilename suffix.
     ].
-    command := command ,
-                ' -C ' , (self possiblyQuotedPath:stFileName asFilename pathName).
-
-    errorStream := 'errorOutput' asFilename writeStream.
+    command := command , ' -C ' , (self possiblyQuotedPath:stFileName asFilename pathName).
 
     Verbose == true ifTrue:[
         Transcript show:'executing: '; showCR:command.
     ].
 
     originator activityNotification:'compiling (stc)'.
-    ok := OperatingSystem 
-                executeCommand:command 
-                inputFrom:nil
-                outputTo:errorStream
-                errorTo:errorStream
-                showWindow:false
-                onError:[:stat| 
-                            executionStatus := stat.
-                            false
-                        ].
 
-    errorStream close.
+    errorOutputFile := Filename tempDirectory / 'stcErrorOutput'. 
+    errorOutputFile writingFileDo:[:errorStream |
+        ok := OperatingSystem 
+                    executeCommand:command 
+                    inputFrom:nil
+                    outputTo:errorStream
+                    errorTo:errorStream
+                    showWindow:false
+                    onError:[:stat| 
+                                self breakPoint:#cg.
+                                executionStatus := stat.
+                                false
+                            ].
+    ].
 
     cFileName asFilename exists ifTrue:[
         ok ifFalse:[
-            Transcript showCR:'Compiler [info]: oops - system says stc failed - but c-file is there ...'.
+            'Compiler [info]: oops - system says stc failed - but c-file is there ...' infoPrintCR.
             ok := true
         ]
     ] ifFalse:[
         ok ifTrue:[
-            Transcript showCR:'Compiler [info]: oops - system says stc ok - but no c-file is there ...'.
+            'Compiler [info]: oops - system says stc ok - but no c-file is there ...' infoPrintCR
         ].
         ok := false
     ].
+    
+    [
+        ok ifFalse:[
+            aBlock value:errorOutputFile
+        ].
+    ] ensure:[
+        errorOutputFile remove.
+    ].
     ^ ok
 
     "Created: / 07-11-2006 / 12:11:24 / cg"
     "Modified: / 08-08-2011 / 22:12:01 / cg"
 !
 
-compileToExe
-    "compile C to exe, using cc"
+compileToExe_onError:aBlock 
+    "compile C to exe, using cc.
+     If any error happens, call aBlock passing it the fileName containing diagnostics"
 
-    |command errorStream ok|
-
-    errorStream := 'errorOutput' asFilename newReadWriteStream.
+    |command errorOutputFile ok|
 
     command := (self possiblyQuotedPath:ccPath) , ' ' , cFlags , ' -D__INCREMENTAL_COMPILE__ ' , (self possiblyQuotedPath:cFileName).
 
@@ -533,35 +639,38 @@
         Transcript show:'executing: ' showCR:command.
     ].
     originator activityNotification:'compiling (' , ccPath , ')'.
-    ok := OperatingSystem 
-                executeCommand:command 
-                inputFrom:nil
-                outputTo:errorStream
-                errorTo:errorStream
-                showWindow:false
-                onError:[:stat| 
-                            executionStatus := stat.
-                            false
-                ].
 
-    ok ifFalse:[
-        errorStream reset.
-        errorStream copyToEndInto:Transcript.
+    errorOutputFile := Filename tempDirectory / 'stcErrorOutput'. 
+    errorOutputFile writingFileDo:[:errorStream |
+        ok := OperatingSystem 
+                    executeCommand:command 
+                    inputFrom:nil
+                    outputTo:errorStream
+                    errorTo:errorStream
+                    showWindow:false
+                    onError:[:stat| 
+                                executionStatus := stat.
+                                false
+                    ].
     ].
-
-    errorStream close.
-
+    
+    [
+        ok ifFalse:[
+            aBlock value:errorOutputFile
+        ].
+    ] ensure:[
+        errorOutputFile remove.
+    ].
     ^ ok
 !
 
-compileToObj
-    "compile C to obj, using cc"
+compileToObj_onError:aBlock
+    "compile C to obj, using cc.
+     If any error happens, call aBlock passing it the fileName containing diagnostics"
 
-    |errorStream ok commandTemplate command ccDefine env|
+    |errorOutputFile ok commandTemplate command ccDefine env|
 
-    errorStream := 'errorOutput' asFilename newReadWriteStream.
-
-    "/ bcc does not like -D__BORLANDC__ (needs to be set to a version, such as 0x0505
+    "/ bcc does not like -D__BORLANDC__ (needs to be set to a version, such as 0x0505)
     "/ others do not need it (is already predefined in the compiler)
     "/ ccDefine := ' -D',ParserFlags usedCompilerDefine.
     "/ so, never redefine ccDefine
@@ -606,50 +715,52 @@
             OperatingSystem setEnvironment: 'PATH' to: path  , ';', ccPath asFilename directory pathName
         ].
     ].
-
-    ok := OperatingSystem 
-                executeCommand:command 
-                inputFrom:nil
-                outputTo:errorStream
-                errorTo:errorStream
-                environment:env
-                showWindow:false
-                onError:
-                    [:stat| 
-                        executionStatus := stat.
-                        false
-                    ].
-
-    ok ifFalse:[
-        errorStream reset.
-        errorStream contents do:[:l | Transcript showCR:(OperatingSystem decodePathOrCommandOutput: l)].
+    
+    errorOutputFile := Filename tempDirectory / 'stcErrorOutput'. 
+    errorOutputFile writingFileDo:[:errorStream |
+        ok := OperatingSystem 
+                    executeCommand:command 
+                    inputFrom:nil
+                    outputTo:errorStream
+                    errorTo:errorStream
+                    environment:env
+                    showWindow:false
+                    onError:
+                        [:stat| 
+                            executionStatus := stat.
+                            false
+                        ].
     ].
-
-    errorStream close.
-
+    
     oFileName asFilename exists ifTrue:[
         ok ifFalse:[
-            Transcript showCR:'Compiler [info]: system says compile failed - but o-file is there ...'.
+            'Compiler [info]: system says compile failed - but o-file is there ...' infoPrintCR.
             ok := true
         ]
     ] ifFalse:[
         ok ifTrue:[
-            Transcript showCR:'Compiler [info]: system says compile ok - but no o-file is there ...'.
+            'Compiler [info]: system says compile ok - but no o-file is there ...' infoPrintCR.
         ].
         ok := false
     ].
+    [
+        ok ifFalse:[
+            aBlock value:errorOutputFile
+        ].
+    ] ensure:[
+        errorOutputFile remove.
+    ].
     ^ ok
 
     "Created: / 07-11-2006 / 12:14:51 / cg"
     "Modified: / 04-01-2016 / 21:12:56 / jv"
 !
 
-compileToS
-    "compile C to assembler, using cc"
+compileToS_onError:aBlock
+    "compile C to assembler, using cc.
+     If any error happens, call aBlock passing it the fileName containing diagnostics"
 
-    |command errorStream ok|
-
-    errorStream := 'errorOutput' asFilename newReadWriteStream.
+    |command errorOutputFile ok|
 
     command := (self possiblyQuotedPath:ccPath) , ' ' , cFlags , ' -D__INCREMENTAL_COMPILE__ -S ' , (self possiblyQuotedPath:cFileName).
 
@@ -657,23 +768,27 @@
         Transcript show:'executing: '; showCR:command.
     ].
     originator activityNotification:'compiling (' , ccPath , ')'.
-    ok := OperatingSystem 
-                executeCommand:command 
-                inputFrom:nil
-                outputTo:errorStream
-                errorTo:errorStream
-                showWindow:false
-                onError:[:stat| 
-                            executionStatus := stat.
-                            false
-                ].
 
-    ok ifFalse:[
-        errorStream reset.
-        errorStream copyToEndInto:Transcript.
+    errorOutputFile := Filename tempDirectory / 'stcErrorOutput'. 
+    errorOutputFile writingFileDo:[:errorStream |
+        ok := OperatingSystem 
+                    executeCommand:command 
+                    inputFrom:nil
+                    outputTo:errorStream
+                    errorTo:errorStream
+                    showWindow:false
+                    onError:[:stat| 
+                                executionStatus := stat.
+                                false
+                    ].
     ].
-
-    errorStream close.
+    [
+        ok ifFalse:[
+            aBlock value:errorOutputFile
+        ].
+    ] ensure:[
+        errorOutputFile remove.
+    ].
     ^ ok
 !
 
@@ -946,6 +1061,73 @@
     "Modified: / 21-12-2013 / 00:08:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
 !
 
+reportCompilationErrorFor:aCommand fromFile:anErrorFilename
+    |eMsg errorMessages lNr|
+
+    (executionStatus notNil and:[executionStatus couldNotExecute]) ifTrue:[
+        eMsg := 'oops, no %1 - cannot create machine code' bindWith:aCommand.
+    ] ifFalse:[
+        errorMessages := anErrorFilename contents 
+                            collect:[:l | OperatingSystem decodePathOrCommandOutput: l ].
+
+        errorMessages notNil ifTrue:[
+            errorMessages := errorMessages reject:[:line | line includesString:'Warning:'].
+
+            errorMessages size > 20 ifTrue:[
+                errorMessages := errorMessages select:[:line | line asLowercase startsWith:'error'].
+                errorMessages size > 20 ifTrue:[
+                    errorMessages := (errorMessages copyTo:20) copyWith:'... more messages skipped'
+                ].
+            ].
+"/                    errorMessages := errorMessages collect:[:line |
+"/                        (line startsWith:(stFileName , ':')) ifTrue:[
+"/                            'Line: ' , (line copyFrom:(stFileName size + 2))
+"/                        ] ifFalse:[
+"/                            line
+"/                        ]
+"/                      ].
+        ].
+        errorMessages isNil ifTrue:[
+            errorMessages := #('')
+        ].
+        errorMessages := (Array with:'Failed to execute: "', aCommand,'"') , errorMessages.
+
+        "/ try to extract a line number"
+        (errorMessages contains:[:line | line includesString:'Borland']) ifTrue:[
+            |i i2 s|
+            i := errorMessages findFirst:[:l | l startsWith:(cFileName,':')].
+            i ~~ 0 ifTrue:[
+                ((errorMessages at:i+1) startsWith:'Error') ifTrue:[
+                    i2 := (errorMessages at:i+1) indexOfSubCollection:(stFileName).
+                    i2 ~~ 0 ifTrue:[
+                        s := (errorMessages at:i+1) copyFrom:(i2+stFileName size+1).
+                        s := s readStream.
+                        lNr := Integer readFrom:s.
+                        s skipSeparators.
+                    ].    
+                ]
+            ].
+        ].
+
+        errorMessages isEmpty ifTrue:[
+            eMsg := 'Error during compilation:\\Unspecified error (no output)' withCRs
+        ] ifFalse:[
+            eMsg := 'Error during compilation:\\' withCRs ,
+                    (errorMessages asStringCollection asString).
+        ].
+    ].
+
+    originator activityNotification:''.
+
+    ParseError new
+        lineNumber:lNr;
+        errorMessage:eMsg;
+        raise.
+
+    "Created: / 07-11-2006 / 12:29:04 / cg"
+    "Modified: / 21-12-2013 / 00:08:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
 setupCompilationCommandArguments
     |stFn libDir incDir incDirArg defs incl opts|
 
@@ -961,7 +1143,7 @@
     cFileName asFilename delete.
 
     "/ stcFlags := '-commonSymbols +sharedLibCode +newIncremental -E:errorOutput -N' , initName .
-    stcFlags := '+newIncremental -E:errorOutput'.
+    stcFlags := '+newIncremental'.
     initName notEmptyOrNil ifTrue:[
         stcFlags := stcFlags,' -N' , initName .
     ].