#lang scheme/base
(require scheme/file
scheme/system
scheme/match)
(provide current-gcc gcc (struct-out exn:fail:process))
(define current-gcc (make-parameter
(or (find-executable-path "gcc")
(find-executable-path "gcc.exe"))))
(define-struct (exn:fail:process exn:fail) (out error-out) #:transparent)
(define (gcc print-source)
(let ([gcc (current-gcc)])
(unless (file-exists? gcc)
(raise (make-exn:fail:filesystem (format "file not found: ~a" gcc)
(current-continuation-marks))))
(let ([ch (make-channel)])
(let-values ([(stdout-read stdout-write) (make-pipe)]
[(stderr-read stderr-write) (make-pipe)])
(thread
(lambda ()
(define executable #f)
(dynamic-wind
void
(lambda ()
(with-handlers ([exn? (lambda (exn) (channel-put ch exn))])
(set! executable (make-temporary-file "mztmp~a.exe" #f (build-path 'same)))
(match-let ([(list _ stdin pid _ control)
(process*/ports (current-output-port) #f stderr-write
(current-gcc) "-x" "c" "-w" "-o" (path->string executable) "-")])
(parameterize ([current-output-port stdin])
(call-with-continuation-barrier print-source))
(flush-output stdin)
(close-output-port stdin)
(control 'wait)
(let ([exit-code (control 'exit-code)])
(unless (zero? exit-code)
(raise (make-exn:fail:process (format "process exited with code ~a" exit-code)
(current-continuation-marks)
stdout-read
stderr-read)))))
(match-let ([(list _ stdin pid _ control)
(process*/ports stdout-write #f stderr-write
(path->string executable))])
(close-output-port stdin)
(channel-put ch #t)
(control 'wait))))
(lambda ()
(with-handlers ([exn? void])
(close-output-port stdout-write))
(with-handlers ([exn? void])
(close-output-port stderr-write))
(when executable
(sleep 3/10)
(with-handlers ([exn? void])
(delete-file executable)))))))
(let ([ack (channel-get ch)])
(if (exn? ack)
(raise ack)
(values stdout-read stderr-read)))))))