So, I'm going to this programming contest at the University of New
Orleans this weekend, and my team wishes to use lisp. The rules are
that any language that can make an exe and read and write to std in can
be used. And fit on a floppy. And run on windows XP. So, this isn't
so good for lisp. I talked to the coordinator, and got permission to
turn in our submissions on either CD or a usb stick, and I'm going to
convince them that a bat file is just as good as an exe. Especially
since one of the officially supported languages is java.
Anyway, tonight I wrote a small program to automate making deliverable
clisp systems. Its not all that complete, but I'd appreciate any feedback.
The code and examples are available at
http://www.andystuff.com/clisp-build.zip and I've included the
build.lisp file below.
;; build.lisp
;; atc 4/13/05
;; System for making a clisp "exe"
;; if I accidentally used clisp internals
;; this code is licensed under the GPL v2 or greater
;; this code is licensed in the public domain.
(defparameter *compiler-dir* "C:\\clisp-2.33.1\\"
"The directory where clisp resides.")
(defun build-distribution (filename)
"builds a bat file for clisp distribution.
Reads a definition file, and makes the distribution.
Format for def file is...
(<app-name> <dest-dir> <full | base>
(<file-to-load>*) | <image.mem>
<entry-function>)
Where app-name is the name of your application,
dest-dir is the directory you wish to store the bundle in,
(please use the correct slash for your system!)
specify if you want a full or base compiler used,
a list of files that should be loaded, in order, or an existing image
and a function with no arguments that will act as
the entry point."
(with-open-file (fp filename)
(let ((data (read fp)))
(when data
(let ((name (first data))
(dir (second data))
(full-p (equalp 'full (third data)))
(files (fourth data))
(entry (fifth data)))
(build-dist name dir full-p files entry))))))
(defun build-dist (name dir full-p files entry)
"Does all the hard work of building the system.
See build-distribution"
(maybe-create-directory dir)
(let ((image (if (listp files)
(progn
;; Have to build a memory image now...
;; So make a lisp file that the compiler will use
;; to generate the image.
(generate-image files (format nil "~A.mem" name)
dir full-p))
(copy-mem-image files dir))))
(build-bat-file name dir image entry)
(copy-runtime-files dir full-p)))
(defun build-bat-file (name dir image entry)
"Builds a clisp batch file"
(with-open-file (stream (format nil "~A~A.bat" dir name)
:direction :output :if-exists :supersede)
(format stream ·@echo off~%~A\\lisp.exe -B \"~A\\\" -M \"~A\\~A\"
--silent -norc -x \"(progn (~A) (values))\"~%"
dir dir dir image entry)))
(defun maybe-create-directory (dir)
"Creates the directory dir if it does not exist."
(unless (directory dir)
(ext:run-program (format nil "mkdir ~A" dir) :indirectp t)))
(defun copy-runtime-files (dst full-p)
"Copies the lisp.exe to the dst directory"
(let ((src (format nil "~A~A\\"
*compiler-dir* (if full-p
"full"
"base"))))
(my-copy-file (format nil "~Alisp.exe" src) dst)))
(defun copy-mem-image (image dst)
"Copies the memory file to the destination directory."
(my-copy-file image dst)
(file-namestring image))
(defun my-copy-file (src dst)
"Copies a src file to a dst file.
dst may be a directory, in which case the file will be
copied to that directory."
(ext:run-program (format nil "copy ~A ~A" src dst) :indirectp t))
(defun generate-image (files image-name dst full-p)
"Calls the correct clisp to build these lisp or fasl files into a
memory image."
(with-open-file (stream (format nil "~Amk-bld-sys.lisp" dst)
:direction :output
:if-exists :supersede)
(format stream "~{(load ~S)~%~}(ext:saveinitmem ~S)"
files (concatenate 'string dst image-name)))
(ext:run-program (format nil "~A ~A ~A"
(concatenate 'string *compiler-dir*
"compiler.bat")
(if full-p "full" "base")
(concatenate
'string
dst "mk-bld-sys.lisp")) :indirectp t)
image-name)