From: Nikhil Ketkar
Subject: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <1140216769.899756.54510@z14g2000cwz.googlegroups.com>
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

From: Rob Warnock
Subject: Re: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <25adnYb_qZyOA2veRVn-vQ@speakeasy.net>
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
From: ········@gmail.com
Subject: Re: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <1140285044.069326.53570@o13g2000cwo.googlegroups.com>
>This seems fine, though as long as you're going to the trouble of
>building a core image...

awsome, thanks for the post, rob

Nick
From: RPG
Subject: Re: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <1140296694.084453.286150@g44g2000cwa.googlegroups.com>
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?
From: Rob Warnock
Subject: Re: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <huidnSVu_7F4rWXeRVn-pQ@speakeasy.net>
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
From: Nikhil Ketkar
Subject: Re: Is this a correct way of delivering CMUCL application ?
Date: 
Message-ID: <1140326042.661347.302340@g43g2000cwa.googlegroups.com>
Thanks..this has helped a lot !!!