gen-class not generating a class

782 views Asked by At

I'm having difficulty referencing classes generated via :gen-class.

The smallest example I can show that demonstrates the problem is:

(defproject test-proj
  :dependencies [[org.clojure/clojure "1.8.0"]] 
  :aot [test-proj.test])

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

(defn -main []
  (println test_proj.test)) ; Error here

The problem is, this yields a ClassNotFoundException on the marked line.

(I tried all different combinations of - and _ in the above file and the project.clj. I still don't fully understand what requires an underscore and what tolerates a dash. Some things seem to roll with dashes and convert them as needed, whereas I know from messing around that in the -main, I need underscores to reference test_proj.test.)

If I go into the project root file, there's no target folder, so it's not generating the class. If I go into the terminal and run lein compile, it generates the needed classes under target, and the above code runs without error. This is a poor workaround though. What if I modify the file and forget to manually recompile it? It's also a pain to have to manually compile it after any time I do a clean.

As a shot in the dark, I tried using compile right underneath the ns macro:

(compile 'test-proj.test)

If I uses dashes, compile seems to do literally nothing. I may be misinterpreting its use, but it doesn't generate class files under target. If I use underscores, it gives an exception saying that the namespace isn't found.

Is there a way to have the classes generated automatically so I don't need to run lein compile everytime? I thought that that's what the :aot in the project.clj did.

1

There are 1 answers

1
Nicolas Modrzyk On BEST ANSWER

With Leiningen, specify :aot settings. :all is the easiest.

project.clj

(defproject test-proj "0.1.0-SNAPSHOT"
  :main test-proj.core
  :aot :all
  :dependencies [[org.clojure/clojure "1.8.0"]])

If you want, you can specify the exact namespaces in an array as seen below:

project.clj

(defproject test-proj "0.1.0-SNAPSHOT"
  :main test-proj.core
  :aot [test-proj.core]
  :dependencies [[org.clojure/clojure "1.8.0"]])

Then the following lein command:

lein compile

Will generate the byte code and .class files as specified in the :aot settings above.

core.clj

(ns test-proj.core
    (:gen-class))

(defn -main[]
  (println test_proj.core)
  (println "Hello, World!"))

You want to see something like the below:

NikoMacBook% lein compile 
Compiling test-proj.core

Once this is done, check the target folder, contains the proper class file, here test_proj/core.class.

NikoMacBook% tree target 
target
├── classes
│   ├── META-INF
│   │   └── maven
│   │       └── test-proj
│   │           └── test-proj
│   │               └── pom.properties
│   └── test_proj
│       ├── core$_main.class
│       ├── core$fn__38.class
│       ├── core$loading__5569__auto____36.class
│       ├── core.class
│       └── core__init.class
└── stale
    └── leiningen.core.classpath.extract-native-dependencies

7 directories, 7 files

The following will run the :main namespace, so test-proj.core.

lein run 

Will output

NikoMacBook% lein run 
Compiling test-proj.core
Compiling test-proj.core
test_proj.core
Hello, World!

Note, that the class is calling itself. Note also that if you do not run lein compile beforehand , it will run by itself.