main.rkt
#lang racket/base

(define main-method (λ args (error "No main method registered!")))
(define lock (make-semaphore 1))

(define (register! method)
  (call-with-semaphore
   lock
   (λ ()
     (when (eq? main-method 'running)
       (error "Main method is already running. Don't register after you run."))
     (set! main-method method))))

(define-syntax-rule (define-main! (args ...) body ...)
  (register!
    (lambda (args ...) body ...)))

(define (vector-apply proc v)
  (call-with-values
   (λ () (vector->values v))
   proc))

(define (run)
  (call-with-semaphore
   lock
   (λ ()
     (let ((method main-method))
       (set! main-method 'running)
       (vector-apply method (current-command-line-arguments))))))

(define-syntax-rule (provide-main)
  (begin
    (define main run)
    (provide main)))

(provide register! run define-main! provide-main)