Sunday, 30 November 2008

AOT problem solved

Thanks to the swift responses of the Clojure google group I have got past my little problem. It was, of course, deceptively simple, but not clear to someone who doesn't do Java programming much.

The problem was basically that whatever I did I could not get Clojure to recognise that the source files existed in the classpath.

When you invoke java with the
-jar
command line option it completely ignores the classpath (both the environment variable, or the
-cp
argument.

So, when compiling my code I simply switch this:


java -cp ./classes:./src -jar ${HOME}/src/clojure/clojure.jar ./compile.clj


.. to this ...


java -cp ./classes:./src:${HOME}/src/clojure/clojure/jar clojure.lang.Script ./compile.clj


For the record the contents of
compile.clj
are as follows:


(binding [*compile-path* "/home/gteale/src/aot_test/classes"]
(compile 'de.teale.test))


I plan to replace that with either ant or lancet shortly.

Caught on a Clojure roller coaster

I was hoping to make some decent progress this weekend with my Clojure code. The plan was to port it to the new AOT model of compilation.

However, my efforts have been frustrated by me not being able to get AOT working. I have posted my problem to the group, so hopefully there will be some solution soon.

Clojure is developing so rapidly it's hard to keep up, I think that's how I got into this mess with AOT. However, for every new problem people are finding solutions that blow me away. This blog post details a really elegant solution to the lack of tail call optimisation for mutually recursive functions:

http://www.windley.com/archives/2008/11/tail_optimized_mutual_recursion_in_clojure.shtml

Thursday, 27 November 2008

AOT is cool, but it breaks some of the below content.

Clojure is a young language, and as such it's developing fast. It's an exhilarating ride to be on, but sometime it means things I've written change.

So, when reading the below posts, please note that the latest revisions to Clojure include the provision of Ahead-Of-Time (AOT) compilation. This will break the compilation mechanisms I used in some of the content below. When I get round to fixing up my programs I'll try an post revised instructions for Jar creation, till then I suggest you check out the docs here for compilation notes.

Sunday, 9 November 2008

On Clojure - part 3 - Qt Designer files and custom slots.

So, as promised, here's a few notes on how I am using Qt Designer with Clojure.
Some important things to remember:

  • You must use Qt Designer with the QtJambi plugins installed. The easiest way to do this is to run designer.sh (Linux / UNIX / Mac OS X) or designer.bat (Windows) from the distribution folder that QtJambi came in. If you've got QtJambi installed as a package under Linux then you may need to check that the QtJambi plugins are correctly installed , they weren't in my case.

  • If you have the QtJambi plugins installed designer should be able to save .jui files instead of .ui files.



I don't intend to tell you how to use Qt Designer, there's a good user manual available.
Once you've put together a UI in Designer plugging it into a clojure application is relatively simple, though there are some subtleties that took me a while to work out (along with a large chunk of time trawling #clojure logs, the wiki and various blog post - thanks to all who share their work!)
What follows is the full source code for an incredibly simple app that uses a single QMainWindow with a Designer derived layout, I'll explain some more after the code:

(gen-and-load-class "foo.gen.Slot"
:methods [["slot" [] Void]])

(ns foo
(:import (foo Ui_MainWindow))
(:import (com.trolltech.qt.gui QApplication QMainWindow))
(:import (com.trolltech.qt.core QCoreApplication))
(:import (foo.gen Slot)))


(def slots
(proxy [Slot] []
(slot [] (prn "Slot Called"))))

(defn init []
(QApplication/initialize (make-array String 0)))

(defn exec []
(QApplication/exec))

(defmacro qt4 [& rest]
`(do
(try (init) (catch RuntimeException e# (println e#)))
~@rest
(exec)))


(def Foo-main
(fn [& args]
(qt4
(let [ui_main (new Ui_MainWindow)
mainWindow (new QMainWindow)]
(. ui_main (setupUi mainWindow))
(let [pushButton (. ui_main pushButton)]
(.. pushButton clicked (connect slots "slot()")))
(. mainWindow (show))))))


This code lives in the package "foo", in the file "Foo.clj". If you're familiar R.P. Dillon's guide to with making Jar's from clojure you'll know that Foo-main is the Main function of the resulting JAR. Notice that we also import Ui_MainWindow from the same package. This is the generated Java code from the Designer file Ui_MainWindow.jui. In order to generate the java code you simply run:


juic Ui_MainWindow.jui


As I want the resulting code to live in a package, "foo", I need to manually add the following line to the top of the resulting file, Ui_MainWindow.java:


package foo;


We also need to arrange for this .java file to be compiled before we can use it. How you use this depends on your build system, but you can choose to just compile it by hand when it changes (as this should be comparitevly rare). I guess you know how, but just for completeness:


javac foo/Ui_MainWindow.java


Now, the qt4 macro I've defined there is directly lifted from Brian Carper's blog posting on using Qt4 in Clojure, and again I won't go into that here. Instead lets look at Foo-main. Note that we create instances of both the Ui_MainWindow class from the generated java code and the QMainWindow class. We call the setupUI method of the Ui_MainWindow class with the QMainWindow class as it's arguement (this essentially fills out the QMainWindow with the layout you put together in designer). Note also that I reference the pushButton widget inside the Ui_MainWindow class.

The remaining interesting thing about this file is that it defines a custom slot. Signals and Slots are fundemental to the way that Qt hangs together. Wiring together the prexisting signals and slots is very easy and can be done either in Designer or in code (as R.P. Dillon's example shows). Making a custom slot turns out to be rather more difficult. I naively assumed that I could just use a proxy around the QMainWindow class and add a slot function there, but this simply doesn't work. Instead I need to use (gen-class) to make a real class and bind a clojure function to it. For convenience I use (gen-and-load-class) - this call generates the bytecode and loads it. You have to pass it a fully qualifed class name - I've found it better to make it a subpackage, so I place it in foo.gen, and therefore the classname is foo.gen.Slot. I also have to give a place holder for the slot method. Confusingly enough I've chosen to call it "slot" here. We pass a vector containing a vector for each method, which in turn contains a method name, a vector of arguements and a return type. The method name will get bound to a function in the current namespace (not foo.gen, but foo) with the name -. In my example code this is contained in the proxy "slots" as the "slot" method. It's possible to just use a normal (defn) for this mapped method, in which case the function name would be "Slot-slot", I just find the proxy cleaner. Lastly you'll see that, back in Foo-main, I connect the pushButton's clicked signal to the custom slot, "slot" in the proxy, "slots". I hope that's clear!

Now all things being equal you should be able to make your JAR and execute the code. I hope that helps someone avoid spending a lot of time trying to work this out.

When I need to implement a custom signal I'll try and write that up too. Till then, ta ta!

Saturday, 8 November 2008

On Clojure - part 2 - Distributing QtJambi with Clojure.

One of the questions I've seen coming up a few times is how to distribute clojure programs. The obvious answer is to build executable JAR files.


I while ago I produced a simple database application for my girlfriends recruitment business, NRecruit. I developed this using Clojure on my Arch Linux based laptop, and deployed to her MacBook running OS X Leopard. The underlying database is sqlite3, but it could just as well be MySQL or anything else that is supported by JDBC. For simplicity I unzip the required JAR files in the root directory of the project and then rebundle them into a single distributable JAR following this guide.


That application is in production use right now, but there have been a number of problems with the Swing based GUI. I have been trying to address them, but I find Swing an unnecessarily painful toolkit to use.


Several years back (circa KDE 2, and early KDE 3) I used to do some development with Qt in C++ and Ruby. I have looked at Qt4 a couple of time before and I still feel that Qt is one of the nicest GUI toolkits out there. So I read this blog entry on using Qt4 with clojure with great excitement I started porting the NRecruit database UI over to Qt.


So far I've hit two issues. The first one (using Qt Designer files from within Clojure) I'll address in a later post; the second one is more fundemental. Distributing QtJambi in your jar has a few gotchas. The most succesful approach I've found is this:



  • unzip the qtjambi-4.4.3_01.jar and qtjambi-linux32-gcc-4.4.3_01.jar files in your projects root directory (where the version number and platform name vary based on the version of QtJambi you're using and the platform you're targetting).

  • When you make your jar file make sure you include the "com" and "lib" directories and the file "qtjambi-deployment.xml"


That leaves me with what I'd describe as a "statically linked" executable (it isn't in any sense statically linked, but the effect is the same).


More later...


On Clojure - part 1.

After many a dalliance with R6RS compliant(ish) Scheme implementations I have found myself inevitably drawn towards as new Lisp dialect instead. While I'm pleased to see Ikarus maturing to the state where it really is a very usable it's not what I've been using to get stuff done. No, instead, I (like everyone else it seems) have fallen for Clojure.


I won't harp on about Clojure - you can read about it everywhere, instead I'll just make some practical notes in the following posts.