I have some CMUCL code which I need to give out for them to duplicate
my experiments.
Everybody uses linux on x86. This is what I did.
1) I compiled and loaded each file in CMUCL
(load (compile-file "file-1.lisp"))
(load (compile-file "file-1.lisp"))
... for all files.
2) I dumped the core image like this
(save-lisp "my-application.core")
3) I wrote a shell script to launch this together like this
lisp -core my-application.core -eval "(main-function $1 $2)"
where main-function is the top level function and the $1, $2 are the
parameters which need to be passed.
4) I send the lisp environment, the core file and this shell script to
the end user.
He launches the shell script with the parameters.
Is this ok?
Thanks,
Nikhil Ketkar
Nikhil Ketkar <············@gmail.com> wrote:
+---------------
| 1) I compiled and loaded each file in CMUCL
| (load (compile-file "file-1.lisp"))
| (load (compile-file "file-1.lisp"))
| ... for all files.
| 2) I dumped the core image like this
| (save-lisp "my-application.core")
|
| 3) I wrote a shell script to launch this together like this
| lisp -core my-application.core -eval "(main-function $1 $2)"
| where main-function is the top level function and the $1, $2 are the
| parameters which need to be passed.
|
| 4) I send the lisp environment, the core file and this shell script to
| the end user. He launches the shell script with the parameters.
| Is this ok?
+---------------
This seems fine, though as long as you're going to the trouble of
building a core image you might as well specify the call of your
MAIN-FUNCTION in the SAVE-LISP call itself, along with a few more
options to make things work more smoothly. So your step #2 might
become:
(flet ((run-main ()
(let ((args (cdr (get-command-line-switch "core"))))
(if args
(apply #'main-function (mapcar #'read-from-string args))
(error "usage: lisp -load my-app.x86f arg1 arg2"))
(unix:unix-exit 0))))
(save-lisp "my-app.core" :init-function #'run-main
:batch-mode t
:print-herald nil
:load-init-file nil))
[Note that I've used CMUCL's command line processing functions, which
are described in section 6.1 "Reading the Command Line" in the CMUCL
User's Manual.]
Then to run it in step #3, you just say the following [I've
included a stub MAIN-FUNCTION that just prints its args]:
$ lisp -core my-app.core 123 465 last-arg '#(9 8 7)'
MAIN-FUNCTION called with:
arg[1]: 123
arg[2]: 465
arg[3]: LAST-ARG
arg[4]: #(9 8 7)
$
[If you were running on FreeBSD instead of Linux, I'd even suggest
using Fred Gilham's "executable" hack, which adds one more argument
to the SAVE-LISP, ":EXECUTABLE T", which writes out a single executable
ELF file that contains both the "lisp" executable and the core file,
but that code hasn't made it into the Linux version yet. However, see
<http://article.gmane.org/gmane.lisp.cmucl.devel/3029/> for Eric Marsden's
version of that, which requires that you be able to rebuild CMUCL...]
Conversely, if you're going to be generating updates of your
appplication fairly frequently and don't want to send a whole
new (*large!*) CMUCL image each time, you might take advantage
of the fact that the CMUCL loader accepts a concatentation of
FASL files as well as a single file. That is:
1. Compile all your ".lisp" files as before, but only LOADing
those needed to compile-file later ones.
2. In the Unix/Linux shell, concatenate all of the ".x86f" FASLs
together into one big one, in the correct order for loading, e.g.:
$ cat file-1.x86f file-2.x86f ... file-N.x86f > my-app.x86f
$
3. Make your wrapper shell script call it this way [note that
it now uses the standard CMUCL distribution "lisp.core"]:
lisp -load my-app.x86f -eval "(main-function $1 $2)"
Then, as needed, you can ship out an updated "my-app.x86f", which
is likely to be a good deal smaller than an entire ".core" file.
To add some command-line processing like that shown above,
write one more tiny Lisp file that parses the CMUCL command
line arguments and passes them to your "main-function",
possibly something like this:
(declaim (ftype function main-function)) ; muffle warning
(defswitch "main") ; we want to parse "-main"
(let ((args (get-command-line-switch "main")))
(if args
(apply #'main-function (mapcar #'read-from-string args))
(error "usage: lisp -load my-app.x86f -main arg1 arg2..."))
(unix:unix-exit 0))
Compile-file that [but *don't* LOAD it!] and concatenate the ".x86f"
onto the end of your "my-app.x86f", and then you can run the whole
thing like this:
$ lisp -load my-app.x86f -main 123 465 last-arg '#(9 8 7)'
; Loading #p"/usr/u/rpw3/my-app.x86f".
MAIN-FUNCTION called with:
arg[1]: 123
arg[2]: 465
arg[3]: LAST-ARG
arg[4]: #(9 8 7)
$
Finally, if you want the app to exit on error (or EOF on stdin) instead
of dropping into the debugger, then also add the "-batch" switch [which
the first example did with (SAVE-LISP ... :BATCH-MODE T)]:
$ lisp -batch -load my-app.x86f -main args...
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Rob Warnock wrote:
> Nikhil Ketkar <············@gmail.com> wrote:
> +---------------
> | 1) I compiled and loaded each file in CMUCL
> | (load (compile-file "file-1.lisp"))
> | (load (compile-file "file-1.lisp"))
> | ... for all files.
> | 2) I dumped the core image like this
> | (save-lisp "my-application.core")
> |
> | 3) I wrote a shell script to launch this together like this
> | lisp -core my-application.core -eval "(main-function $1 $2)"
> | where main-function is the top level function and the $1, $2 are the
> | parameters which need to be passed.
> |
> | 4) I send the lisp environment, the core file and this shell script to
> | the end user. He launches the shell script with the parameters.
> | Is this ok?
> +---------------
>
> This seems fine, though as long as you're going to the trouble of
> building a core image you might as well specify the call of your
> MAIN-FUNCTION in the SAVE-LISP call itself, along with a few more
> options to make things work more smoothly. So your step #2 might
> become:
...snip...
Wow! This was such an excellent article about application delivery for
CMUCL. Would you consider putting it into the CMUCL documentation
and/or putting it on Cliki?
RPG <·········@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > This seems fine, though as long as you're going to the trouble of
| > building a core image you might as well specify the call of your
| > MAIN-FUNCTION in the SAVE-LISP call itself...
|
| Wow! This was such an excellent article about application delivery for
| CMUCL. Would you consider putting it into the CMUCL documentation
| and/or putting it on Cliki?
+---------------
I'll see what I can so. For some time I've been meaning to
write up something related to this, a "-script" hack that
works with a standard distribution core file [the hack is
implemented in the "site-init" file], that's used this way
[it also allows FASLs]:
$ cat demo
#!/usr/local/bin/cmucl -script
(format t "~s run with ~a args:~%" *script-name* (length *script-args*))
(loop for i from 0 and arg in *script-args* do
(format t "arg[~a]: ~s~%" i arg))
$ demo foo 'bar baz' gorp
"demo" run with 3 args:
arg[0]: "foo"
arg[1]: "bar baz"
arg[2]: "gorp"
$
It's what I use for all my miscellaneous "scripting" these days...
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607