[Openmcl-devel] Create a CCL image that can quickly load Cocoa using a command-line workflow
gb at clozure.com
Thu Jun 13 01:27:54 CDT 2013
In the past, I'm fairly sure that I've seen cases where command-line arguments
(I'm fairly sure that "-e" was involved) were processed by the Cocoa libraries;
I don't think that this was documented, and it looked like some code that
was leftover from NeXTSTEP and seemed to have something to do with specifying
files to be opened. I have no idea whether that (Cocoa) code even worked, but
it tended to produce some cryptic error messages when people did things like:
$ ccl -e "(require :cocoa)"
). I didn't see that when I tried your change on OSX 10.6.8; I don't know
whether that means that some old code has been removed or whether I just didn't
stumble over it.
If it isn't clear: this is only likely to work to the extent that it does
if you run the executable from the shell; the usual startup code creates
a listener thread that effectively uses file descriptors 0 and 1 (and sometimes
2) as standard I/O. If you launch the application by double-clicking on it,
fd 0 will be open to /dev/null and the listener thread will probably get repeated
EOFs and terminate the application. If you never enter that REPL, this may not
matter; if your test code tried to enter a break loop, it might.)
One of the time-consuming things that happens when one does
? (require "COCOA")
is that all of the Cocoa class and method declarations in the .cdb files are
parsed, the corresponding classes are looked up in the ObjC runtime, the
functions accessible via #/ are defined, etc. Some of that happens again
when a saved image that's had that stuff happen is loaded again (more or
less the same declared classes/methods are processed again, but this time
all that needs to be done is to find the current foreign address of the
things in question.) That should all happen automatically and happens at
a lower level than the startup code that you changed.
I was always taught that if you have nothing nice to say about an Emacs mode it's
best to say nothing at all.
Anyhow, I didn't see an obvious problem with what you did (modulo what's noted
above.) I wouldn't be totally shocked if that changes due to either a change
in Cocoa or a change in CCL in the future. I don't know of a compelling reason
to make such a change to CCL, but such a reason wouldn't have to be overwhelmingly
Another approach to this that may be more robust depends on the fact that
the IDE loads init files: if "home:ccl-ide-init.lisp" or the corresponding
FASL exists around the time that the Cocoa event loop starts, that file
is loaded in the event thread; if "home:ccl-init" exists, that file is
loaded in the initial Cocoa listener thread when that thread starts up.
It's probably more general to load your tests via command-line arguments,
but that may also be more fragile.
On Wed, 12 Jun 2013, Clayton Stanley wrote:
> Figured out the last issue. SLIME was interacting with the image, and causing stderr
> (I presume) to get all messed up. I built the App within slime and then launched it
> from the Terminal. Turns out this is not a good idea...
> If you build the app from Terminal and then launch it from Terminal (or double click),
> everything works.
> So if anyone else wants an image that can be launched from the command line, that has
> Cocoa loaded, that has the Terminal REPL decoupled from the GUI REPL, and that allows
> command-line arguments (like -l) to be given on the command line, these steps worked
> for me:
>  Patch the build-ide function in the GUI package in cocoa-ide/start.lisp. Comment
> out all but the first argument to save-application in that function.
>  Launch CCL from the terminal, load the patched function, then execute (require
>  Then you can run Clozure\ CL64.app/Contents/MacOS/dx86cl64 -e
> '(gui::start-cocoa-ide)' -l test.lisp -e '(quit)'
> On Wed, Jun 12, 2013 at 10:34 PM, Clayton Stanley <cstanley at cstanley.no-ip.biz> wrote:
> Thanks for the hint to launch the executable within the built App.
> This approach is almost working.?
> Here's what I would like to be able to do:
> ./[path-to-executable] -l tests.lisp -e '(quit)'
> And have :cocoa already loaded in the image associated with that executable.
> Here is what I have:
> Clozure\ CL64.app/Contents/MacOS/dx86cl64 -e '(gui::start-cocoa-ide)' -l
> test.lisp -e '(quit)'
> This works except that I do not get any feedback (i.e., the program freezes) if
> I cause lisp to throw an exception. Interesting thing is, if I just build a
> default :cocoa app (with require :cocoa-application), I still do not get any
> feedback if I cause lisp to throw an exception when typing in the GUI REPL. The
> whole program freezes when I do this. Is this issue?reproducible?on a machine
> other than mine? If I can fix this, then I have a working solution.
> Here is how I got there:
> Comment out all but the first argument in the save-application call in the
> build-ide function:
> $ git df cocoa-ide/start.lisp
> diff --git a/cocoa-ide/start.lisp b/cocoa-ide/start.lisp
> index 478d8d4..2e59715 100644
> --- a/cocoa-ide/start.lisp
> +++ b/cocoa-ide/start.lisp
> @@ -147,9 +147,10 @@
> ? ? ?(ccl:copy-file (ccl::kernel-path) kernel-file :if-exists :supersede?
> ? ? ? ? ? ? ? ? ? ? :preserve-attributes t)
> ? ? ?(save-application image-file
> - ? ? ? ? ? ? ? ? ? ? :application-class 'cocoa-ide
> - ? ? ? ? ? ? ? ? ? ? #+windows-target #+windows-target
> - ? ? ? ? ? ? ? ? ? ? :application-type :gui)))
> + ? ? ? ? ? ? ? ? ? ? ;:application-class 'cocoa-ide
> + ? ? ? ? ? ? ? ? ? ? ;#+windows-target #+windows-target
> + ? ? ? ? ? ? ? ? ? ? ;:application-type :gui
> + ? ? ? ? ? ? ? ? ? ? ?)))
> This change ensures that the CCL Gui App Window doesn't automatically launch
> when running the executable. This is necessary because I would like to pass
> arguments (the -l in particular) when launching the executable. If the arguments
> to save-application are uncommented, I am not able to pass any arguments when
> launching the executable, which means that I cannot pass the important -l
> argument that loads the test file.?
> This change also decouples the terminal from the CCL GUI App listener (like it
> is with Slime), so that compiler warnings stdout, etc. go to the Terminal, and
> not the GUI App. This is important when running the tests, because I want all of
> that trace to persist after the CCL image closes. If it is placed on the GUI
> App's listener window, it?disappears?after running through the tests. If it's
> placed on the Terminal, I can redirect it to a file easily, or simply just
> scroll through the output after the tests run.
> I'll be interested to see if anyone can reproduce the last issue I found. Simple
> test procedure:
>  Launch CCL
>  (require :cocoa-application)
>  double click the new app
>  type (lslslslslsls) in the listener
>  does it hang?
> On Wed, Jun 12, 2013 at 5:09 PM, Gary Byers <gb at clozure.com> wrote:
> You can run any bundled application from the command line via:
> $ /path/to/application.app/Contents/MacOS/executable-name
> $ /path/to/ClozureCL\ 64.app/Contents/MacOS/dx86cl64
> What happens in that case is very similar to what happens when you
> on the application's icon; the primary difference is that the
> standard I/O fds remain attached to the terminal/shell
> buffer/whatever. ?I don't
> know if that actually helps you, because I don't really understand
> what you're
> trying to do; do you plan on having the application run an event
> loop, or do
> you plan on having it run your tests ?
> That may or may not be a fair question. ?Another such question: is
> what you're
> trying to do the sort of thing that could/should be done via
> AppleScript/Automator ?
> Whatever the answers to these questions, you may find it worthwhile
> to try
> to understand what happens when (REQUIRE "COCOA") is called and when
> a bundled
> CCL application starts up. ?(Just guessing clearly doesn't work ...)
> On Wed, 12 Jun 2013, Clayton Stanley wrote:
> I am running a suite of testing code that uses Cocoa in CCL.
> To make sure each test is
> isolated from the others, I would like to launch a CCL
> instance for each test, which
> means I'll need to launch CCL about 15 times to run all tests.
> A (require :cocoa) call on my machine takes about 15 seconds
> to compile and load all
> Cocoa code. This is fine when running a development instance
> of CCL through Slime for
> an entire day, but is too slow when having to do this 15 times
> to run through the test
> suite (especially since the time required for most of the
> tests to run is less than a
> second; and I'd like to run the test suite more often than
> once a day).
> I would like a CCL .image file that has :cocoa loaded in it
> that I can launch from the
> command line when running the tests.?
> I tried commenting out (gui::start-cocoa-ide) in
> cocoa-ide/cocoa.lisp. Then (require
> :cocoa), then (save-application ...). The idea was to get all Cocoa
> lisp code compiled
> and loaded into the saved core. Then when launching the modified
> image, I'd type
> (gui::start-cocoa-ide), and the Cocoa window would quickly boot up.
> But this didn't
> work. The Cocoa window doesn't appear on my machine, and CCL becomes
> after calling (gui::start-cocoa-ide).
> Any other ideas?
> I can't use the CCL App from the App Store or a double-clickable CCL
> GUI Application
> because I need to be able to launch the ccl image from the command
> line. This is so
> that I can run the test suite from the command line (so that it can
> be automated and
> incorporated into the build scripts), and also so that the workflow
> to run the test
> suite matches a Slime development workflow, where Slime is simply
> pointed to a lisp
> image (and not a GUI app) when booting up.
> Thanks for the help,
More information about the Openmcl-devel