18
votes

I'm a beginner with clojure, only starting it yesterday.

I have gathered that a simple way to create a standalone app is with leiningen lein new foo.

I tried to create a hello world test project with leiningen. I added :main and :aot directives to project.clj, added :gen-class to the core.clj file and tried lein run, but I get errors about class definition not found.

Exception in thread "main" java.lang.NoClassDefFoundError: 
Caused by: java.lang.ClassNotFoundException: 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)

The core.clj file

(ns test.core
  (:gen-class))
(defn -main [& args] (println "Hello main"))

And the project.clj file

(defproject test "1.0.0-SNAPSHOT"
  :description "FIXME: write description"
  :main test.core
  :aot [test.core]
  :dependencies [[org.clojure/clojure "1.2.1"]])

Edit: After further testing, it seems like copying the project to my desktop works as is, which I think points to that the environment on my laptop is somehow borked, but I don't know how.

The environment on desktop is clojure from repositories and leiningen from AUR. On laptop the clojure is from clojure.org and leining is from github.

4
What is your CLASSPATH set to?deong
@deong my $HOME/bin/clj file has "CLASSPATH=.:$CLASSPATH"Masse
What happens if you just do an "export CLASSPATH=.:$CLASSPATH" in the shell and then run 'lein run'? I don't believe leiningen calls the clj shell script to run your program. I think it calls java directly with the clojure jar file as an argument.deong
@deong Still the same. Or rather, it can't even create the jar file. lein compile gives the same errorMasse
Hmm...I'm drawing a blank then. The clojure code looks right to me.deong

4 Answers

34
votes

[UPDATE April 2013]

Leiningen 2, which has been officially released for some time, includes the concept of project templates. By default, Leiningen provides an app template that provides what you need out of the box. Try:

lein new app my-project

You will see that Leiningen creates the familiar project template, but also includes:

  • The default namespace of my-project.core as the :main entry in your project.clj file
  • The :gen-class form in the namespace declaration of my-project.core
  • A default -main function in the my-project.core namespace

For those who cannot yet use Leiningen 2, the lein-newnew plugin provides an equivalent experience under Leiningen 1.

[/UPDATE]

To build a project that, when run, prints "Hello World!", you'd do as follows (revision of your process above):

Setup

lein new my-project
cd my-project
lein deps

You should now have a basic structure in place and the Clojure jar in your lib folder.

Write a Function

Now edit src/my_project/core.clj with your editor of choice, adding the following below the (ns ...) form:

(defn -main []
  (println "Hello World!"))

This function is inside your my-project.core namespace. To ensure this gets run as your main, let's add a gen-class parameter to your namespace definition at the top, so that it now looks like this at the top of core.clj:

(ns my-project.core
  (:gen-class :main true))

So all together, your core.clj file looks like this:

(ns my-project.core
  (:gen-class :main true))

(defn -main []
  (println "Hello World!"))

Configure it as the Main Function

Once you've got src/my_project/core.clj edited as above, you need to tell Leiningen (the build tool) where the "main" function for your project lives. Here's an example defproject form that does this:

(defproject my-project "1.0.0-SNAPSHOT"
  :description "My Project"
  :dependencies [[org.clojure/clojure "1.2.1"]]
  :main my-project.core)

Now the -main function inside my-project.core becomes the entry-point for your program.

Run It

You can now have two options for running this project:

  • Use lein run at the command-line while at the root of your my-project project
  • Create a standalone jar file by running lein uberjar. You can then run the resultant jar file by running java -jar my-project-1.0.0-SNAPSHOT-standalone.jar
1
votes

Figured it out. I had the latest leiningen from git, which was borked somehow. I checked out the 1.6.1 tag and ran self-install, and now it works.

0
votes

You say above

lein new foo

what you mean is

lein new test
0
votes

I missed it, You named your project test, you can't do that change the name to something else it will work.