16
votes

I'm feeling slightly silly here, but I can't get Clojure Hello World to compile.

Directory structure:

hello-world/
  clojure-1.1.0.jar
  build/
    classes/
  src/
    test/
      hello.clj

hello.clj:

(ns test.hello
  (:gen-class))

(defn -main [& args]
  (println "Hello" (nth args 0)))

Interaction:

$ cd hello-world
[hello-world]$ java -cp ./clojure-1.1.0.jar:./build/classes:./src clojure.main
Clojure 1.1.0
user=> (require 'test.hello)
nil
user=> (test.hello/-main "there")
Hello there
nil
user=> (compile 'test.hello)
java.io.IOException: No such file or directory (hello.clj:2)
user=> *compile-path*
"classes"
user=> (doseq [p (.split (System/getProperty "java.class.path") ":")] (println p))
./clojure-1.1.0.jar
./build/classes
./src
nil

So I can load and call the file from the REPL, but it doesn't compile.

According to clojure.org, compilation needs

  • namespace must match classpath-relative file path - check
  • *compile-path* must be on the classpath - check
  • :gen-class argument to the ns form - check

I found this post from a year back, as far as I can tell I'm doing exactly the same, but it doesn't work.

What am I missing?

System: OS X 10.6, Java 1.6.0, Clojure 1.1

3
Looks like I can't accept my own answer, so I'll have to leave the question open until someone else chimes in. - j-g-faustus
It's also relevant to note that you rarely need to AOT compile Clojure code. Clojure code will run just fine without being compiled, and that is the way you should run it. Some specific Clojure Java interop features actually require that your code be AOT compiled, but if you aren't using those features, don't bother compiling your code. If you want an executable jar, you can just AOT compile a main file with just a -main function to run the application. However, assembla.com/spaces/clojure/tickets/… - Rayne

3 Answers

11
votes

Why you don't use Leiningen? It's much easier to use it, than compile code manually. You can use my article about it as introduction...

22
votes

Got it, there's a fourth requirement:

  • *compile-path* is resolved relative to the JVMs working directory, normally the directory where java is started. Or by REPL: (System/getProperty "user.dir"),

So this works:

user=> (set! *compile-path* "build/classes")     
"build/classes"
user=> (compile 'test.hello)
test.hello
1
votes

To run clojure file

clojure filename.clj