build: Prepare for autoconfiscation.
authorJan Nieuwenhuizen <janneke@gnu.org>
Sat, 21 Jul 2018 16:28:47 +0000 (18:28 +0200)
committerJan Nieuwenhuizen <janneke@gnu.org>
Sat, 21 Jul 2018 16:28:47 +0000 (18:28 +0200)
Make build system more in alignment with how autotools work.  This
will make transition easier.

* mes/module/mes/boot-0.scm.in: Update from module/mes/boot-0.scm.
* scripts/mescc.in: Update from scripts/mescc.
* build-aux/pre-inst-env.in: New file.
* build-aux/cc-mes.sh: Use pre-inst-env.
* configure: Substitute new .in files.
* install.sh: Do not substitute mescc, boot-0.scm.

.gitignore
GNUmakefile
build-aux/cc-mes.sh
build-aux/check-mes.sh
build-aux/pre-inst-env.in [new file with mode: 0644]
configure
install.sh
mes/module/mes/boot-0.scm [deleted file]
mes/module/mes/boot-0.scm.in [new file with mode: 0644]
scripts/mescc [deleted file]
scripts/mescc.in [new file with mode: 0755]

index 37a55e4a8837243a88e1b43a0bc172a68f6a4b73..86f93cb20d1b6ce7bdc87ed526db14bcc64cab1d 100644 (file)
@@ -67,3 +67,7 @@
 /doc/mes.pdf
 /doc/mescc.1
 /doc/version.texi
+
+/pre-inst-env
+/mes/module/mes/boot-0.scm
+/scripts/mescc
index db7dd516ce15301778d9b49fa2b81bee2ca8b5eb..b3d3fac5de198229206d65ab5cc56d2ca0806b67 100644 (file)
@@ -64,8 +64,7 @@ clean-go:
 check:
        ./check.sh
 
-
-install:
+install: src/mes
        ./install.sh
 
 .config.make: ./configure
index 3203741fe5869e04028d98da9372e779c8a1a778..2553760892b0e684131089822387e3fd33f6082a 100755 (executable)
@@ -63,20 +63,20 @@ else
 fi
 
 if [ -n "$PREPROCESS" ]; then
-    bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -E -o "$o.E" "$c".c
-    bash $MESCC $MES_CFLAGS -S "$o".E
-    bash $MESCC $MES_CFLAGS -c -o "$o".${p}o "$o".S
+    ./pre-inst-env bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -E -o "$o.E" "$c".c
+    ./pre-inst-env bash $MESCC $MES_CFLAGS -S "$o".E
+    ./pre-inst-env bash $MESCC $MES_CFLAGS -c -o "$o".${p}o "$o".S
     if [ -z "$NOLINK" ]; then
-        bash $MESCC $MES_CFLAGS -o "$o".${p}out "$o".${p}o $MES_LIBS
+        ./pre-inst-env bash $MESCC $MES_CFLAGS -o "$o".${p}out "$o".${p}o $MES_LIBS
     fi
 elif [ -n "$COMPILE" ]; then
-    bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -S -o "$o.S" "$c".c
-    bash $MESCC $MES_CFLAGS -c -o "$o".${p}o "$o".S
+    ./pre-inst-env bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -S -o "$o.S" "$c".c
+    ./pre-inst-env bash $MESCC $MES_CFLAGS -c -o "$o".${p}o "$o".S
     if [ -z "$NOLINK" ]; then
-        bash $MESCC $MES_CFLAGS -o "$o".${p}out "$o".${p}o $MES_LIBS
+        ./pre-inst-env bash $MESCC $MES_CFLAGS -o "$o".${p}out "$o".${p}o $MES_LIBS
     fi
 elif [ -z "$NOLINK" ]; then
-    bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -o "$o".${p}out "$c".c $MES_LIBS
+    ./pre-inst-env bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -o "$o".${p}out "$c".c $MES_LIBS
 else
-    bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -c -o "$o".${p}o "$c".c
+    ./pre-inst-env bash $MESCC $MES_CPPFLAGS $MES_CFLAGS -c -o "$o".${p}o "$c".c
 fi
index 94f7c8ebfd69ef2beb21e7bb2f7f38ca9db5c694..0d5aaffb1be10fa45e418de6ba5f7b59823d6b46 100755 (executable)
@@ -73,7 +73,7 @@ for t in $tests; do
         echo $t: [SKIP];
         continue
     fi
-    sh "$t" &> $t.${mes}log
+    ./pre-inst-env sh "$t" &> $t.${mes}log
     r=$?
     total=$((total+1))
     if [ $r = 0 ]; then
diff --git a/build-aux/pre-inst-env.in b/build-aux/pre-inst-env.in
new file mode 100644 (file)
index 0000000..6ad5835
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Mes --- Maxwell Equations of Software
+# Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+#
+# This file is part of Mes.
+#
+# Mes 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 3 of the License, or (at
+# your option) any later version.
+#
+# Mes 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 Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+abs_top_srcdir="$(cd "@abs_top_srcdir@" > /dev/null; pwd -P)"
+abs_top_builddir="$(cd "@abs_top_builddir@" > /dev/null; pwd -P)"
+
+MES_PREFIX=mes
+export MES_PREFIX
+
+GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/module${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH"
+GUILE_LOAD_PATH="$abs_top_srcdir/module${GUILE_LOAD_PATH:+:}$GUILE_LOAD_PATH"
+export GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH
+
+PATH="$abs_top_builddir/scripts:$PATH"
+export PATH
+
+LANG=
+LC_ALL=
+
+exec "$@"
index 44c8f8b2ae82c5105d1f27acad8d175a24ab66d7..3d8e7cc2955d4439f2f175948f3f3fa50a38d2a0 100755 (executable)
--- a/configure
+++ b/configure
@@ -46,6 +46,7 @@ exec ${GUILE-guile} -L . --no-auto-compile -e '(configure)' -s "$0" ${1+"$@"}
 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (configure)
+  #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
   #:use-module (ice-9 and-let-star)
   #:use-module (ice-9 curried-definitions)
@@ -54,12 +55,18 @@ exec ${GUILE-guile} -L . --no-auto-compile -e '(configure)' -s "$0" ${1+"$@"}
   #:use-module (ice-9 optargs)
   #:use-module (ice-9 popen)
   #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 regex)
   #:export (main))
 
+(define* (PATH-search-path name #:key (default name) warn?)
+  (or (search-path (string-split (getenv "PATH") #\:) name)
+      (and (and warn? (format (current-error-port) "warning: not found: ~a\n" name))
+           default)))
+
 (define *shell* "sh")
 (define PACKAGE "mes")
 (define VERSION "0.16.1")
-(define GUILE (or (getenv "guile") "guile"))
+(define GUILE (PATH-search-path (or (getenv "guile") "guile")))
 (define GUILE_EFFECTIVE_VERSION (effective-version))
 
 (define prefix "/usr/local")
@@ -128,11 +135,6 @@ exec ${GUILE-guile} -L . --no-auto-compile -e '(configure)' -s "$0" ${1+"$@"}
                                        (char-set-complement (char-set #\.)))))
             (map string->number version)))
 
-(define* (PATH-search-path name #:key (default name) warn?)
-  (or (search-path (string-split (getenv "PATH") #\:) name)
-      (and (and warn? (format (current-error-port) "warning: not found: ~a\n" name))
-           default)))
-
 (define optional '())
 (define required '())
 (define* (check-version name expected
@@ -261,8 +263,22 @@ Some influential environment variables:
   TINYCC_SEED       location of tinycc-seed
 " PACKAGE VERSION (getenv "prefix")))
 
+(define* (substitute file-name pairs
+                     #:key (target (if (string-suffix? ".in" file-name)
+                                       (string-drop-right file-name 3) target)))
+  (with-output-to-file target
+    (lambda _
+      (display
+       (fold (lambda (o result)
+               (regexp-substitute/global #f (car o) result 'pre (cdr o) 'post))
+             (with-input-from-file file-name read-string) pairs)))))
+
 (define (main args)
   (let* ((CC (or (getenv "CC") "gcc"))
+         (srcdir (dirname (car (command-line))))
+         (abs-top-srcdir (canonicalize-path srcdir))
+         (builddir (getcwd))
+         (abs-top-builddir (canonicalize-path builddir))
          (BUILD_TRIPLET %host-type)
          (ARCH (car (string-split BUILD_TRIPLET #\-)))
          (options (parse-opts args))
@@ -271,6 +287,13 @@ Some influential environment variables:
          (prefix (option-ref options 'prefix prefix))
          (infodir (option-ref options 'infodir infodir))
          (sysconfdir (option-ref options 'sysconfdir sysconfdir))
+         (datadir (string-append prefix "/share/mes"))
+         (moduledir (string-append datadir"module"))
+         (guile-effective-version (effective-version))
+         (guile-site-dir (if (equal? prefix ".") (canonicalize-path ".")
+                             (string-append prefix "/share/guile/site/" guile-effective-version)))
+         (guile-site-ccache-dir (if (equal? prefix ".") (canonicalize-path ".")
+                                    (string-append prefix "/lib/guile/" guile-effective-version "/site-ccache")))
          (verbose? (option-ref options 'verbose #f))
          (with-courage? (option-ref options 'with-courage #f))
          (disable-silent-rules? (option-ref options 'disable-silent-rules #f))
@@ -281,6 +304,7 @@ Some influential environment variables:
     (let ((CC32 (or (getenv "CC32")
                     (if (member ARCH '("i686" "arm")) (string-append BUILD_TRIPLET "-" CC)
                         "i686-unknown-linux-gnu-gcc")))
+          (BASH (or (getenv "BASH") "bash"))
           (HELP2MAN (or (getenv "HELP2MAN") "help2man"))
           (TCC (or (getenv "TCC") "tcc"))
           (MAKEINFO (or (getenv "MAKEINFO") "makeinfo"))
@@ -319,6 +343,9 @@ Some influential environment variables:
       (when (and (not (member ARCH '("i686" "x86_64"))) (not with-courage?))
         (stderr "platform not supported: ~a, try --with-courage\n" ARCH)
         (exit 1))
+      (if (check-version "bash" '(2))
+          (set! BASH (PATH-search-path BASH))
+          (set! BASH #f))
       (if (not (check-version CC '(4 8) #:optional? #t))
           (set! CC #f))
       (when CC
@@ -349,6 +376,8 @@ Some influential environment variables:
           (stdout "prefix:=~a\n" (gulp-pipe (string-append "echo " prefix)))
           (stdout "infodir:=~a\n" infodir)
           (stdout "mandir:=~a\n" mandir)
+          (stdout "datadir:=~a\n" datadir)
+          (stdout "moduledir:=~a\n" moduledir)
           (stdout "sysconfdir:=~a\n" sysconfdir)
 
           (stdout "ARCH:=~a\n" ARCH)
@@ -378,6 +407,25 @@ Some influential environment variables:
           (when HEX2FLAGS (stdout "HEX2FLAGS:=~a\n" HEX2FLAGS))
           (when M1FLAGS (stdout "M1FLAGS:=~a\n" M1FLAGS))
           (when MES_CFLAGS (stdout "MES_CFLAGS:=~a\n" MES_CFLAGS))))
+      (let ((pairs `(("@abs_top_srcdir@" . ,abs-top-srcdir)
+                     ("@abs_top_builddir@" . ,abs-top-builddir)
+                     ("@BASH@" . ,BASH)
+                     ("@GUILE@" . ,GUILE)
+                     ("@guile_site_dir@" . ,guile-site-dir)
+                     ("@guile_site_ccache_dir@" . ,guile-site-ccache-dir)
+                     ("@VERSION@" . ,VERSION)
+                     ("mes/module/" . ,(string-append moduledir "/")))))
+        (for-each (lambda (o)
+                    (substitute o pairs)
+                    (chmod (string-drop-right o 3) #o755))
+                  '(
+                    "build-aux/pre-inst-env.in"
+                    "mes/module/mes/boot-0.scm.in"
+                    "scripts/mescc.in"
+                    )))
+      (chmod "build-aux/pre-inst-env" #o755)
+      (rename-file "build-aux/pre-inst-env" "pre-inst-env")
+      (chmod "scripts/mescc" #o755)
       (format (current-output-port)
               "\nRun:
   ~a            to build mes
index 88bb2db8a50c92752cb6692cd51ab3369f077ab5..60c01c2464af979a220dd584d0dfbabbf3911dcb 100755 (executable)
@@ -15,24 +15,45 @@ MES_PREFIX=${MES_PREFIX-$prefix/share/mes}
 MES_SEED=${MES_SEED-../MES-SEED}
 TINYCC_SEED=${TINYCC_SEED-../TINYCC-SEED}
 
-GUILE_EFFECTIVE_VERSION=${GUILE_EFFECTIVE_VERSION-2.2}
-datadir=${moduledir-$prefix/share/mes}
-docdir=${moduledir-$prefix/share/doc/mes}
+GUILE_EFFECTIVE_VERSION=${GUILE_EFFECTIVE_VERSION-$(guile -c '(display (effective-version))')}
+bindir=${bindir-$prefix/bin}
+datadir=${datadir-$prefix/share/mes}
+docdir=${docdir-$prefix/share/doc/mes}
+infodir=${infodir-$prefix/share/info}
 mandir=${mandir-$prefix/share/man}
 moduledir=${moduledir-$datadir/module}
 guile_site_dir=${guile_site_dir-$prefix/share/guile/site/$GUILE_EFFECTIVE_VERSION}
 guile_site_ccache_dir=${guile_site_ccache_dir-$prefix/lib/guile/$GUILE_EFFECTIVE_VERSION/site-ccache}
-docdir=${moduledir-$prefix/share/doc/mes}
 
-mkdir -p $DESTDIR$prefix/bin
-cp src/mes $DESTDIR$prefix/bin/mes
+mkdir -p $DESTDIR$bindir
+cp src/mes $DESTDIR$bindir/mes
+cp scripts/mescc $DESTDIR$bindir/mescc
 
-mkdir -p $DESTDIR$prefix/lib
-mkdir -p $DESTDIR$MES_PREFIX/lib
-cp scripts/mescc $DESTDIR$prefix/bin/mescc
+sed \
+    -e "s,^#! /bin/sh,#! $SHELL," \
+    scripts/diff.scm > $DESTDIR$bindir/diff.scm
+chmod -w+x $DESTDIR$bindir/diff.scm
+
+
+mkdir -p $docdir
+cp\
+    AUTHORS\
+    BOOTSTRAP\
+    COPYING\
+    HACKING\
+    INSTALL\
+    NEWS\
+    README\
+    $DESTDIR$docdir
 
-mkdir -p $DESTDIR$MES_PREFIX
-tar -cf- doc include lib scaffold | tar -xf- -C $DESTDIR$MES_PREFIX
+if [ -f ${top_builddest}ChangeLog ]; then
+    cp ${top_builddest}ChangeLog $DESTDIR$docdir
+else
+    cp ChangeLog $DESTDIR$docdir
+fi
+
+tar -cf- include lib | tar -xf- -C $DESTDIR$MES_PREFIX
+tar -cf- scaffold --exclude='*.gcc*' --exclude='*.mes*' | tar -xf- -C $DESTDIR$MES_PREFIX
 tar -cf- --exclude='*.go' module | tar -xf- -C $DESTDIR$MES_PREFIX
 tar -cf- -C mes module | tar -xf- -C $DESTDIR$MES_PREFIX
 
@@ -41,38 +62,9 @@ mkdir -p $DESTDIR$guile_site_ccache_dir
 tar -cf- -C module --exclude='*.go' . | tar -xf- -C $DESTDIR$guile_site_dir
 tar -cf- -C module --exclude='*.scm' . | tar -xf- -C $DESTDIR$guile_site_ccache_dir
 
-chmod +w $DESTDIR$prefix/bin/mescc
-sed \
-    -e "s,^#! /bin/sh,#! $SHELL," \
-    -e "s,@datadir@,$datadir,g" \
-    -e "s,@docdir@,$docdir,g" \
-    -e "s,@guile_site_ccache_dir@,$guile_site_ccache_dir,g" \
-    -e "s,@guile_site_dir@,$guile_site_dir,g" \
-    -e "s,@moduledir@,$moduledir,g" \
-    -e "s,@prefix@,$prefix,g" \
-    -e "s,@VERSION@,$VERSION,g" \
-    scripts/mescc > $DESTDIR$prefix/bin/mescc
-chmod +w $DESTDIR$moduledir/mes/boot-0.scm
-sed \
-    -e "s,^#! /bin/sh,#! $SHELL," \
-    -e "s,mes/module/,$moduledir/," \
-    -e "s,@datadir@,$datadir,g" \
-    -e "s,@docdir@,$docdir,g" \
-    -e "s,@guile_site_ccache_dir@,$guile_site_ccache_dir,g" \
-    -e "s,@guile_site_dir@,$guile_site_dir,g" \
-    -e "s,@moduledir@,$moduledir,g" \
-    -e "s,@prefix@,$prefix,g" \
-    -e "s,@VERSION@,$VERSION,g" \
-    mes/module/mes/boot-0.scm > $DESTDIR$moduledir/mes/boot-0.scm
-
-sed \
-    -e "s,^#! /bin/sh,#! $SHELL," \
-    scripts/diff.scm > $DESTDIR$prefix/bin/diff.scm
-chmod -w+x $DESTDIR$prefix/bin/diff.scm
-
 if [ -f doc/mes.info ]; then
     mkdir -p $DESTDIR$prefix/share/info
-    tar -cf- doc/mes.info* doc/images | tar -xf- --strip-components=1 -C $DESTDIR$prefix/share/info
+    tar -cf- doc/mes.info* doc/images | tar -xf- --strip-components=1 -C $DESTDIR$infodir
     install-info --info-dir=$DESTDIR$prefix/share/info doc/mes.info
 fi
 
diff --git a/mes/module/mes/boot-0.scm b/mes/module/mes/boot-0.scm
deleted file mode 100644 (file)
index a27566e..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-;;; -*-scheme-*-
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; This file is part of Mes.
-;;;
-;;; Mes 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 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes 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 Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; read-0.mes - bootstrap reader.  This file is read by a minimal
-;;; core reader.  It only supports s-exps and line-comments; quotes,
-;;; character literals, string literals cannot be used here.
-
-;;; Code:
-
-;; boot-00.scm
-(define mes %version)
-
-(define (defined? x)
-  (assq x (current-module)))
-
-(define (cond-expand-expander clauses)
-  (if (defined? (car (car clauses)))
-      (cdr (car clauses))
-      (cond-expand-expander (cdr clauses))))
-
-(define-macro (cond-expand . clauses)
-  (cons 'begin (cond-expand-expander clauses)))
-;; end boot-00.scm
-
-;; boot-01.scm
-(define (pair? x) (eq? (core:type x) <cell:pair>))
-(define (not x) (if x #f #t))
-
-(define (display x . rest)
-  (if (null? rest) (core:display x)
-      (core:display-port x (car rest))))
-
-(define (write x . rest)
-  (if (null? rest) (core:write x)
-      (core:write-port x (car rest))))
-
-(define (list->string lst)
-  (core:make-cell <cell:string> lst 0))
-
-(define (integer->char x)
-  (core:make-cell <cell:char> 0 x))
-
-(define (newline . rest)
-  (core:display (list->string (list (integer->char 10)))))
-
-(define (string->list s)
-  (core:car s))
-
-(define (cadr x) (car (cdr x)))
-
-(define (map1 f lst)
-  (if (null? lst) (list)
-      (cons (f (car lst)) (map1 f (cdr lst)))))
-
-(define (map f lst)
-  (if (null? lst) (list)
-      (cons (f (car lst)) (map f (cdr lst)))))
-
-(define (cons* . rest)
-  (if (null? (cdr rest)) (car rest)
-      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
-
-(define (apply f h . t)
-  (if (null? t) (core:apply f h (current-module))
-      (apply f (apply cons* (cons h t)))))
-
-(define (append . rest)
-  (if (null? rest) '()
-      (if (null? (cdr rest)) (car rest)
-          (append2 (car rest) (apply append (cdr rest))))))
-;; end boot-01.scm
-
-;; boot-02.scm
-(define-macro (and . x)
-  (if (null? x) #t
-      (if (null? (cdr x)) (car x)
-          (list (quote if) (car x) (cons (quote and) (cdr x))
-                #f))))
-
-(define-macro (or . x)
-  (if (null? x) #f
-      (if (null? (cdr x)) (car x)
-          (list (list (quote lambda) (list (quote r))
-                      (list (quote if) (quote r) (quote r)
-                            (cons (quote or) (cdr x))))
-                (car x)))))
-
-(define-macro (module-define! module name value)
-  ;;(list 'define name value)
-  #t)
-
-(define-macro (mes-use-module module)
-  #t)
-;; end boot-02.scm
-
-;; boot-0.scm
-(define (primitive-eval e) (core:eval e (current-module)))
-(define eval core:eval)
-
-(define (current-output-port) 1)
-(define (current-error-port) 2)
-(define (port-filename port) "<stdin>")
-(define (port-line port) 0)
-(define (port-column port) 0)
-(define (ftell port) 0)
-(define (false-if-exception x) x)
-
-(define (cons* . rest)
-  (if (null? (cdr rest)) (car rest)
-      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
-
-(define (apply f h . t)
-  (if (null? t) (core:apply f h (current-module))
-      (apply f (apply cons* (cons h t)))))
-
-(define-macro (cond . clauses)
-  (list 'if (pair? clauses)
-        (list (cons
-               'lambda
-               (cons
-                '(test)
-                (list (list 'if 'test
-                            (if (pair? (cdr (car clauses)))
-                                (if (eq? (car (cdr (car clauses))) '=>)
-                                    (append2 (cdr (cdr (car clauses))) '(test))
-                                    (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
-                                (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
-                            (if (pair? (cdr clauses))
-                                (cons 'cond (cdr clauses)))))))
-              (car (car clauses)))))
-
-(define else #t)
-
-(define-macro (load file)
-  (list 'begin
-        (list 'if (list 'and (list getenv "MES_DEBUG")
-                        (list not (list equal2? (list getenv "MES_DEBUG") "0"))
-                        (list not (list equal2? (list getenv "MES_DEBUG") "1")))
-              (list 'begin
-                    (list core:display-error ";;; read ")
-                    (list core:display-error file)
-                    (list core:display-error "\n")))
-     (list 'primitive-load file)))
-
-(define-macro (include file) (list 'load file))
-
-(define (append . rest)
-  (if (null? rest) '()
-      (if (null? (cdr rest)) (car rest)
-          (append2 (car rest) (apply append (cdr rest))))))
-
-(define (string->list s)
-  (core:car s))
-
-(define %prefix (getenv "MES_PREFIX"))
-(define %moduledir
-  (if (not %prefix) "mes/module/"
-      (list->string
-       (append (string->list %prefix) (string->list "/module/" )))))
-
-(include (list->string
-          (append2 (string->list %moduledir) (string->list "mes/type-0.mes"))))
-
-(define (symbol->string s)
-  (apply string (symbol->list s)))
-
-(define (string-append . rest)
-  (apply string (apply append (map1 string->list rest))))
-
-(define %version (if (eq? (car (string->list "@VERSION@")) #\@) "git"
-                     "@VERSION@"))
-(define (effective-version) %version)
-
-(if (list 'and (list getenv "MES_DEBUG")
-          (list not (list equal2? (list getenv "MES_DEBUG") "0"))
-          (list not (list equal2? (list getenv "MES_DEBUG") "1")))
-    (begin
-      (core:display-error ";;; %moduledir=")
-      (core:display-error %moduledir)
-      (core:display-error "\n")))
-
-(define-macro (include-from-path file)
-  (list 'load (list string-append %moduledir file)))
-
-(define (string-join lst infix)
-  (if (null? lst) ""
-      (if (null? (cdr lst)) (car lst)
-          (string-append (car lst) infix (string-join (cdr lst) infix)))))
-
-(include-from-path "mes/module.mes")
-
-(mes-use-module (mes base))
-(mes-use-module (mes quasiquote))
-(mes-use-module (mes let))
-(mes-use-module (mes scm))
-(mes-use-module (srfi srfi-1))
-(mes-use-module (srfi srfi-13))
-(mes-use-module (mes fluids))
-(mes-use-module (mes catch))
-(mes-use-module (mes posix))
-
-(define-macro (include-from-path file)
-  (let loop ((path (cons* %moduledir "module" (string-split (or (getenv "GUILE_LOAD_PATH")) #\:))))
-    (cond ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 2)) string->number))
-           (core:display-error (string-append "include-from-path: " file " [PATH:" (string-join path ":") "]\n")))
-          ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 1)) string->number))
-           (core:display-error (string-append "include-from-path: " file "\n"))))
-    (if (null? path) (error "include-from-path: not found: " file)
-        (let ((file (string-append (car path) "/" file)))
-          (if (access? file R_OK) `(load ,file)
-              (loop (cdr path)))))))
-
-(define-macro (define-module module . rest)
-  `(if ,(and (pair? module)
-             (= 1 (length module))
-             (symbol? (car module)))
-       (define (,(car module) . arguments) (main (command-line)))))
-
-(define-macro (use-modules . rest) #t)
-
-(mes-use-module (mes getopt-long))
-
-(define %main #f)
-(primitive-load 0)
-(let ((tty? (isatty? 0)))
-  (define (parse-opts args)
-    (let* ((option-spec
-            '((no-auto-compile)
-              (compiled-path (single-char #\C) (value #t))
-              (dump)
-              (help (single-char #\h))
-              (load)
-              (load-path (single-char #\L) (value #t))
-              (main (single-char #\e) (value #t))
-              (source (single-char #\s) (value #t))
-              (version (single-char #\V)))))
-      (getopt-long args option-spec #:stop-at-first-non-option #t)))
-  (define (source-arg? o)
-    (equal? "-s" o))
-  (let* ((s-index (list-index source-arg? %argv))
-         (args (if s-index (list-head %argv (+ s-index 2)) %argv))
-         (options (parse-opts args))
-         (main (option-ref options 'main #f))
-         (source (option-ref options 'source #f))
-         (files (if s-index (list-tail %argv (+ s-index 1))
-                    (option-ref options '() '())))
-         (help? (option-ref options 'help #f))
-         (usage? (and (not help?) (null? files) (not tty?) (not main)))
-         (version? (option-ref options 'version #f)))
-    (or
-     (and version?
-          (display (string-append "mes (Mes) " %version "\n"))
-          (exit 0))
-     (and (or help? usage?)
-          (display "Usage: mes [OPTION]... [FILE]...
-Evaluate code with Mes, interactively or from a script.
-
-  [-s] FILE           load source code from FILE, and exit
-  --                  stop scanning arguments; run interactively
-
-The above switches stop argument processing, and pass all
-remaining arguments as the value of (command-line).
-
-  --dump              dump binary program to stdout
-  -e,--main=MAIN      after reading script, apply MAIN to command-line arguments
-  -h, --help          display this help and exit
-  --load              load binary program [module/mes/boot-0.32-mo]
-  -L,--load-path=DIR  add DIR to the front of the module load path
-  -v, --version       display version information and exit
-
-Ignored for Guile compatibility:
-  --auto-compile
-  --fresh-auto-compile
-  --no-auto-compile
-  -C,--compiled-path=DIR
-" (or (and usage? (current-error-port)) (current-output-port)))
-          (exit (or (and usage? 2) 0)))
-     options)
-    (if main (set! %main main))
-    (and=> (option-ref options 'load-path #f)
-           (lambda (dir)
-             (setenv "GUILE_LOAD_PATH" (string-append dir ":" (getenv "GUILE_LOAD_PATH")))))
-    (cond ((pair? files)
-           (let* ((file (car files))
-                  (port (if (equal? file "-") 0
-                            (open-input-file file))))
-             (set! %argv files)
-             (set-current-input-port port)))
-          ((and (null? files) tty?)
-
-           (mes-use-module (mes repl))
-           (set-current-input-port 0)
-           (repl))
-          (else #t))))
-(primitive-load 0)
-(primitive-load (open-input-string %main))
diff --git a/mes/module/mes/boot-0.scm.in b/mes/module/mes/boot-0.scm.in
new file mode 100644 (file)
index 0000000..a27566e
--- /dev/null
@@ -0,0 +1,315 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes 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 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes 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 Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; read-0.mes - bootstrap reader.  This file is read by a minimal
+;;; core reader.  It only supports s-exps and line-comments; quotes,
+;;; character literals, string literals cannot be used here.
+
+;;; Code:
+
+;; boot-00.scm
+(define mes %version)
+
+(define (defined? x)
+  (assq x (current-module)))
+
+(define (cond-expand-expander clauses)
+  (if (defined? (car (car clauses)))
+      (cdr (car clauses))
+      (cond-expand-expander (cdr clauses))))
+
+(define-macro (cond-expand . clauses)
+  (cons 'begin (cond-expand-expander clauses)))
+;; end boot-00.scm
+
+;; boot-01.scm
+(define (pair? x) (eq? (core:type x) <cell:pair>))
+(define (not x) (if x #f #t))
+
+(define (display x . rest)
+  (if (null? rest) (core:display x)
+      (core:display-port x (car rest))))
+
+(define (write x . rest)
+  (if (null? rest) (core:write x)
+      (core:write-port x (car rest))))
+
+(define (list->string lst)
+  (core:make-cell <cell:string> lst 0))
+
+(define (integer->char x)
+  (core:make-cell <cell:char> 0 x))
+
+(define (newline . rest)
+  (core:display (list->string (list (integer->char 10)))))
+
+(define (string->list s)
+  (core:car s))
+
+(define (cadr x) (car (cdr x)))
+
+(define (map1 f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map1 f (cdr lst)))))
+
+(define (map f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map f (cdr lst)))))
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+;; end boot-01.scm
+
+;; boot-02.scm
+(define-macro (and . x)
+  (if (null? x) #t
+      (if (null? (cdr x)) (car x)
+          (list (quote if) (car x) (cons (quote and) (cdr x))
+                #f))))
+
+(define-macro (or . x)
+  (if (null? x) #f
+      (if (null? (cdr x)) (car x)
+          (list (list (quote lambda) (list (quote r))
+                      (list (quote if) (quote r) (quote r)
+                            (cons (quote or) (cdr x))))
+                (car x)))))
+
+(define-macro (module-define! module name value)
+  ;;(list 'define name value)
+  #t)
+
+(define-macro (mes-use-module module)
+  #t)
+;; end boot-02.scm
+
+;; boot-0.scm
+(define (primitive-eval e) (core:eval e (current-module)))
+(define eval core:eval)
+
+(define (current-output-port) 1)
+(define (current-error-port) 2)
+(define (port-filename port) "<stdin>")
+(define (port-line port) 0)
+(define (port-column port) 0)
+(define (ftell port) 0)
+(define (false-if-exception x) x)
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define-macro (cond . clauses)
+  (list 'if (pair? clauses)
+        (list (cons
+               'lambda
+               (cons
+                '(test)
+                (list (list 'if 'test
+                            (if (pair? (cdr (car clauses)))
+                                (if (eq? (car (cdr (car clauses))) '=>)
+                                    (append2 (cdr (cdr (car clauses))) '(test))
+                                    (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
+                                (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
+                            (if (pair? (cdr clauses))
+                                (cons 'cond (cdr clauses)))))))
+              (car (car clauses)))))
+
+(define else #t)
+
+(define-macro (load file)
+  (list 'begin
+        (list 'if (list 'and (list getenv "MES_DEBUG")
+                        (list not (list equal2? (list getenv "MES_DEBUG") "0"))
+                        (list not (list equal2? (list getenv "MES_DEBUG") "1")))
+              (list 'begin
+                    (list core:display-error ";;; read ")
+                    (list core:display-error file)
+                    (list core:display-error "\n")))
+     (list 'primitive-load file)))
+
+(define-macro (include file) (list 'load file))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+
+(define (string->list s)
+  (core:car s))
+
+(define %prefix (getenv "MES_PREFIX"))
+(define %moduledir
+  (if (not %prefix) "mes/module/"
+      (list->string
+       (append (string->list %prefix) (string->list "/module/" )))))
+
+(include (list->string
+          (append2 (string->list %moduledir) (string->list "mes/type-0.mes"))))
+
+(define (symbol->string s)
+  (apply string (symbol->list s)))
+
+(define (string-append . rest)
+  (apply string (apply append (map1 string->list rest))))
+
+(define %version (if (eq? (car (string->list "@VERSION@")) #\@) "git"
+                     "@VERSION@"))
+(define (effective-version) %version)
+
+(if (list 'and (list getenv "MES_DEBUG")
+          (list not (list equal2? (list getenv "MES_DEBUG") "0"))
+          (list not (list equal2? (list getenv "MES_DEBUG") "1")))
+    (begin
+      (core:display-error ";;; %moduledir=")
+      (core:display-error %moduledir)
+      (core:display-error "\n")))
+
+(define-macro (include-from-path file)
+  (list 'load (list string-append %moduledir file)))
+
+(define (string-join lst infix)
+  (if (null? lst) ""
+      (if (null? (cdr lst)) (car lst)
+          (string-append (car lst) infix (string-join (cdr lst) infix)))))
+
+(include-from-path "mes/module.mes")
+
+(mes-use-module (mes base))
+(mes-use-module (mes quasiquote))
+(mes-use-module (mes let))
+(mes-use-module (mes scm))
+(mes-use-module (srfi srfi-1))
+(mes-use-module (srfi srfi-13))
+(mes-use-module (mes fluids))
+(mes-use-module (mes catch))
+(mes-use-module (mes posix))
+
+(define-macro (include-from-path file)
+  (let loop ((path (cons* %moduledir "module" (string-split (or (getenv "GUILE_LOAD_PATH")) #\:))))
+    (cond ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 2)) string->number))
+           (core:display-error (string-append "include-from-path: " file " [PATH:" (string-join path ":") "]\n")))
+          ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 1)) string->number))
+           (core:display-error (string-append "include-from-path: " file "\n"))))
+    (if (null? path) (error "include-from-path: not found: " file)
+        (let ((file (string-append (car path) "/" file)))
+          (if (access? file R_OK) `(load ,file)
+              (loop (cdr path)))))))
+
+(define-macro (define-module module . rest)
+  `(if ,(and (pair? module)
+             (= 1 (length module))
+             (symbol? (car module)))
+       (define (,(car module) . arguments) (main (command-line)))))
+
+(define-macro (use-modules . rest) #t)
+
+(mes-use-module (mes getopt-long))
+
+(define %main #f)
+(primitive-load 0)
+(let ((tty? (isatty? 0)))
+  (define (parse-opts args)
+    (let* ((option-spec
+            '((no-auto-compile)
+              (compiled-path (single-char #\C) (value #t))
+              (dump)
+              (help (single-char #\h))
+              (load)
+              (load-path (single-char #\L) (value #t))
+              (main (single-char #\e) (value #t))
+              (source (single-char #\s) (value #t))
+              (version (single-char #\V)))))
+      (getopt-long args option-spec #:stop-at-first-non-option #t)))
+  (define (source-arg? o)
+    (equal? "-s" o))
+  (let* ((s-index (list-index source-arg? %argv))
+         (args (if s-index (list-head %argv (+ s-index 2)) %argv))
+         (options (parse-opts args))
+         (main (option-ref options 'main #f))
+         (source (option-ref options 'source #f))
+         (files (if s-index (list-tail %argv (+ s-index 1))
+                    (option-ref options '() '())))
+         (help? (option-ref options 'help #f))
+         (usage? (and (not help?) (null? files) (not tty?) (not main)))
+         (version? (option-ref options 'version #f)))
+    (or
+     (and version?
+          (display (string-append "mes (Mes) " %version "\n"))
+          (exit 0))
+     (and (or help? usage?)
+          (display "Usage: mes [OPTION]... [FILE]...
+Evaluate code with Mes, interactively or from a script.
+
+  [-s] FILE           load source code from FILE, and exit
+  --                  stop scanning arguments; run interactively
+
+The above switches stop argument processing, and pass all
+remaining arguments as the value of (command-line).
+
+  --dump              dump binary program to stdout
+  -e,--main=MAIN      after reading script, apply MAIN to command-line arguments
+  -h, --help          display this help and exit
+  --load              load binary program [module/mes/boot-0.32-mo]
+  -L,--load-path=DIR  add DIR to the front of the module load path
+  -v, --version       display version information and exit
+
+Ignored for Guile compatibility:
+  --auto-compile
+  --fresh-auto-compile
+  --no-auto-compile
+  -C,--compiled-path=DIR
+" (or (and usage? (current-error-port)) (current-output-port)))
+          (exit (or (and usage? 2) 0)))
+     options)
+    (if main (set! %main main))
+    (and=> (option-ref options 'load-path #f)
+           (lambda (dir)
+             (setenv "GUILE_LOAD_PATH" (string-append dir ":" (getenv "GUILE_LOAD_PATH")))))
+    (cond ((pair? files)
+           (let* ((file (car files))
+                  (port (if (equal? file "-") 0
+                            (open-input-file file))))
+             (set! %argv files)
+             (set-current-input-port port)))
+          ((and (null? files) tty?)
+
+           (mes-use-module (mes repl))
+           (set-current-input-port 0)
+           (repl))
+          (else #t))))
+(primitive-load 0)
+(primitive-load (open-input-string %main))
diff --git a/scripts/mescc b/scripts/mescc
deleted file mode 100755 (executable)
index 3079e44..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-#! /bin/sh
-# -*-scheme-*-
-if [ -n "$BUILD_DEBUG" ]; then
-    set -x
-fi
-prefix=${prefix-@prefix@}
-if [ "@prefix@" = @prefix""@ -o ! -d "$prefix/share/mes/module" ]
-then
-    MES_PREFIX=${MES_PREFIX-$(cd $(dirname $0)/.. && pwd)/mes}
-else
-    MES_PREFIX=${MES_PREFIX-$prefix/share/mes}
-fi
-export MES_PREFIX
-mes_p=$(command -v mes)
-
-guile_site_dir=${guile_site_dir-@guile_site_dir@}
-[ "$guile_site_dir" = @"guile_site_dir"@ ] && guile_site_dir=$(dirname $0)/../module
-GUILE_LOAD_PATH=$guile_site_dir:$GUILE_LOAD_PATH
-
-if [ '(' -z "$mes_p" -a -z "$MES" ')' -o "$MES" = "guile" -o "$MES" = "mes.guile" ]; then
-    guile_site_ccache_dir=${guile_site_ccache_dir-@guile_site_ccache_dir@}
-    [ "$guile_site_ccache_dir" = @"guile_site_ccache_dir"@ ] && guile_site_ccache_dir=$(dirname $0)/../module
-    GUILE_LOAD_COMPILED_PATH=$guile_site_ccache_dir:$GUILE_LOAD_COMPILED_PATH
-    GUILE_AUTO_COMPILE=${GUILE_AUTO_COMPILE-0}
-    export GUILE_AUTO_COMPILE
-    exec ${GUILE-guile} -L $guile_site_dir -e '(mescc)' -s "$0" "$@"
-else
-    MES=${MES-$(dirname $0)/mes}
-    exec ${MES-mes} -e '(mescc)' -s $0 "$@"
-fi
-!#
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; This file is part of Mes.
-;;;
-;;; Mes 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 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes 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 Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-(define-module (mescc)
-  #:use-module (ice-9 getopt-long)
-  #:use-module (mes misc)
-  #:use-module (mescc mescc)
-  #:export (main))
-
-(define %prefix (or (getenv "MES_PREFIX")
-                    (if (string-prefix? "@prefix" "@prefix@")
-                        ""
-                        "@prefix@/share/mes")))
-
-(define %version (if (string-prefix? "@VERSION" "@VERSION@") "git"
-                     "@VERSION@"))
-
-(cond-expand
- (mes
-  (define (set-port-encoding! port encoding) #t)
-  (mes-use-module (mes guile))
-  (mes-use-module (mes misc))
-  (mes-use-module (mes getopt-long))
-  (mes-use-module (mes display))
-  (mes-use-module (mescc mescc)))
- (guile
-  (define-macro (mes-use-module . rest) #t)))
-
-(format (current-error-port) "mescc[~a]...\n" %scheme)
-
-(define (parse-opts args)
-  (let* ((option-spec
-          '((assemble (single-char #\c))
-            (compile (single-char #\S))
-            (define (single-char #\D) (value #t))
-            (debug-info (single-char #\g))
-            (help (single-char #\h))
-            (include (single-char #\I) (value #t))
-            (library-dir (single-char #\L) (value #t))
-            (library (single-char #\l) (value #t))
-            (preprocess (single-char #\E))
-            (output (single-char #\o) (value #t))
-            (version (single-char #\V))
-            (verbose (single-char #\v))
-            (write (single-char #\w) (value #t))))
-         (options (getopt-long args option-spec))
-         (help? (option-ref options 'help #f))
-         (files (option-ref options '() '()))
-         (usage? (and (not help?) (null? files)))
-         (version? (option-ref options 'version #f)))
-    (or
-     (and version?
-          (format (current-output-port) "mescc (mes) ~a\n" %version))
-     (and (or help? usage?)
-          (format (or (and usage? (current-error-port)) (current-output-port)) "\
-Usage: mescc [OPTION]... FILE...
-  -c                 preprocess, compile and assemble only; do not link
-  -D DEFINE[=VALUE]  define DEFINE [VALUE=1]
-  -E                 preprocess only; do not compile, assemble or link
-  -g                 add debug info [GDB, objdump] TODO: hex2 footer
-  -h, --help         display this help and exit
-  -I DIR             append DIR to include path
-  -L DIR             append DIR to library path
-  -l LIBNAME         link with LIBNAME
-  -o FILE            write output to FILE
-  -S                 preprocess and compile only; do not assemble or link
-  -v, --version      display version and exit
-  -w,--write=TYPE    dump Nyacc AST using TYPE {pretty-print,write}
-
-Environment variables:
-
-  MES=BINARY         run on mes-executable BINARY {mes,guile}
-  MES_DEBUG=LEVEL    show debug output with verbosity LEVEL {0..5}
-  NYACC_TRACE=1      show Nyacc progress
-")
-          (exit (or (and usage? 2) 0)))
-     options)))
-
-(define (main args)
-  (let* ((options (parse-opts args))
-         (options (acons 'prefix %prefix options))
-         (preprocess? (option-ref options 'preprocess #f))
-         (compile? (option-ref options 'compile #f))
-         (assemble? (option-ref options 'assemble #f))
-         (verbose? (option-ref options 'verbose (getenv "MES_DEBUG"))))
-    (when verbose?
-      (setenv "NYACC_TRACE" "yes")
-      (format (current-error-port) "options=~s\n" options))
-    (cond (preprocess? (mescc:preprocess options))
-          (compile? (mescc:compile options))
-          (assemble? (mescc:assemble options))
-          (else (mescc:link options)))))
-'done
diff --git a/scripts/mescc.in b/scripts/mescc.in
new file mode 100755 (executable)
index 0000000..aa87632
--- /dev/null
@@ -0,0 +1,133 @@
+#! @BASH@
+# -*-scheme-*-
+if [ -n "$BUILD_DEBUG" ]; then
+    set -x
+fi
+prefix=${prefix-@prefix@}
+MES_PREFIX=${MES_PREFIX-$prefix/share/mes}
+export MES_PREFIX
+mes_p=$(command -v mes)
+
+guile_site_dir=${guile_site_dir-@guile_site_dir@}
+GUILE_LOAD_PATH=$guile_site_dir:$GUILE_LOAD_PATH
+
+if [ '(' -z "$mes_p" -a -z "$MES" ')' -o "$MES" = "guile" -o "$MES" = "mes.guile" ]; then
+    guile_site_ccache_dir=${guile_site_ccache_dir-@guile_site_ccache_dir@}
+    GUILE_LOAD_COMPILED_PATH=$guile_site_ccache_dir:$GUILE_LOAD_COMPILED_PATH
+    GUILE_AUTO_COMPILE=${GUILE_AUTO_COMPILE-0}
+    export GUILE_AUTO_COMPILE
+    exec ${GUILE-guile} -L $guile_site_dir -e '(mescc)' -s "$0" "$@"
+else
+    MES=${MES-$(dirname $0)/mes}
+    exec ${MES-mes} -e '(mescc)' -s $0 "$@"
+fi
+!#
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes 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 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes 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 Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (mescc)
+  #:use-module (ice-9 getopt-long)
+  #:use-module (mes misc)
+  #:use-module (mescc mescc)
+  #:export (main))
+
+(define %prefix (or (getenv "MES_PREFIX")
+                    (if (string-prefix? "@prefix" "@prefix@")
+                        ""
+                        "@prefix@/share/mes")))
+
+(define %version (if (string-prefix? "@VERSION" "@VERSION@") "git"
+                     "@VERSION@"))
+
+(cond-expand
+ (mes
+  (define (set-port-encoding! port encoding) #t)
+  (mes-use-module (mes guile))
+  (mes-use-module (mes misc))
+  (mes-use-module (mes getopt-long))
+  (mes-use-module (mes display))
+  (mes-use-module (mescc mescc)))
+ (guile
+  (define-macro (mes-use-module . rest) #t)))
+
+(format (current-error-port) "mescc[~a]...\n" %scheme)
+
+(define (parse-opts args)
+  (let* ((option-spec
+          '((assemble (single-char #\c))
+            (compile (single-char #\S))
+            (define (single-char #\D) (value #t))
+            (debug-info (single-char #\g))
+            (help (single-char #\h))
+            (include (single-char #\I) (value #t))
+            (library-dir (single-char #\L) (value #t))
+            (library (single-char #\l) (value #t))
+            (preprocess (single-char #\E))
+            (output (single-char #\o) (value #t))
+            (version (single-char #\V))
+            (verbose (single-char #\v))
+            (write (single-char #\w) (value #t))))
+         (options (getopt-long args option-spec))
+         (help? (option-ref options 'help #f))
+         (files (option-ref options '() '()))
+         (usage? (and (not help?) (null? files)))
+         (version? (option-ref options 'version #f)))
+    (or
+     (and version?
+          (format (current-output-port) "mescc (mes) ~a\n" %version))
+     (and (or help? usage?)
+          (format (or (and usage? (current-error-port)) (current-output-port)) "\
+Usage: mescc [OPTION]... FILE...
+  -c                 preprocess, compile and assemble only; do not link
+  -D DEFINE[=VALUE]  define DEFINE [VALUE=1]
+  -E                 preprocess only; do not compile, assemble or link
+  -g                 add debug info [GDB, objdump] TODO: hex2 footer
+  -h, --help         display this help and exit
+  -I DIR             append DIR to include path
+  -L DIR             append DIR to library path
+  -l LIBNAME         link with LIBNAME
+  -o FILE            write output to FILE
+  -S                 preprocess and compile only; do not assemble or link
+  -v, --version      display version and exit
+  -w,--write=TYPE    dump Nyacc AST using TYPE {pretty-print,write}
+
+Environment variables:
+
+  MES=BINARY         run on mes-executable BINARY {mes,guile}
+  MES_DEBUG=LEVEL    show debug output with verbosity LEVEL {0..5}
+  NYACC_TRACE=1      show Nyacc progress
+")
+          (exit (or (and usage? 2) 0)))
+     options)))
+
+(define (main args)
+  (let* ((options (parse-opts args))
+         (options (acons 'prefix %prefix options))
+         (preprocess? (option-ref options 'preprocess #f))
+         (compile? (option-ref options 'compile #f))
+         (assemble? (option-ref options 'assemble #f))
+         (verbose? (option-ref options 'verbose (getenv "MES_DEBUG"))))
+    (when verbose?
+      (setenv "NYACC_TRACE" "yes")
+      (format (current-error-port) "options=~s\n" options))
+    (cond (preprocess? (mescc:preprocess options))
+          (compile? (mescc:compile options))
+          (assemble? (mescc:assemble options))
+          (else (mescc:link options)))))
+'done