5
votes

I'm trying to make a stand alone jar from my bare-bones Clojure project using the Leiningen plugin in Intellij's Cursive.

To create the project, I just created the project.clj file, opened it, and Cursive offered to import it as a project.

project.clj:

(defproject WaterTimer "1"
  :description "A timer that reminds you to drink water"
  :main tone-producer/main)

tone-producer.clj:

(ns tone-producer
  (:require [general-helpers :as g])

  (:import [javax.sound.midi MidiSystem
                             Synthesizer
                             MidiChannel])
  (:gen-class))

(defn main [& args]
  (println "Test!"))

When I run the "uberjar" task, I get the following output:

Warning: specified :main without including it in :aot. Implicit AOT of :main will be removed in Leiningen 3.0.0. If you only need AOT for your uberjar, consider adding :aot :all into your :uberjar profile instead. Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method. Created C:\Users\slomi\IdeaProjects\WaterTimer\target\WaterTimer-1.jar Created C:\Users\slomi\IdeaProjects\WaterTimer\target\WaterTimer-1-standalone.jar

I also tried changing the main function to have the default name, and omit the name from the defproject:

(defproject WaterTimer "1"
  :description "A timer that reminds you to drink water"
  :main tone-producer)

(ns tone-producer
      (:require [general-helpers :as g])

      (:import [javax.sound.midi MidiSystem
                                 Synthesizer
                                 MidiChannel])
      (:gen-class))

    (defn -main [& args]
      (println "Test!"))

But now I get the error:

Error: Could not find or load main class clojure.main Compilation failed: Subprocess failed

The structure is:

  • WaterTimer
    • src
      • tone-producer.clj
    • project.clj
    • target

Any guidance here would be appreciated.

2
try re-naming main -main / or in your 2nd approch remove the :main from project.clj - EDIT: wait isn't there a src/<ns>/core.clj normally - your project layout looks oddbirdspider
if I do lein new watertimer I get gist.github.com/birdspider/dcb987f881199f0a6721af4d8fd41a10 - maybe you can try to init the project that way.birdspider
further your defproject is missing the clojure :dependencies (i.e. :dependencies [[org.clojure/clojure "1.8.0"]]) therefor you get the second Errorbirdspider
@birdspider core.clj is just a random name lein uses because no other name is generic enough, it's actually kind of annoying that people keep itnoisesmith

2 Answers

4
votes

For creating uberjars, the project file should have the :aot keyword enabling ahead of time compilation.

Here is an output from my project.clj file.

(defproject jdbc "0.1.0-SNAPSHOT"
  :description "JDBC Project"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [org.clojure/java.jdbc "0.6.1"]
                 [postgresql "9.3-1102.jdbc41"]
                 [com.mchange/c3p0 "0.9.5.2"]
                 [byte-streams "0.2.2"]]
  :main jdbc.core
  :aot [jdbc.core])

Note the :main and :aot entries. Also it needs to be -main as already stated by birdspider.

3
votes

After a bit of fiddling

  • I dropped (:require [general-helpers :as g]) since its not necessary to demostrate the issue
  • Error: Could not find or load main class clojure.main Compilation failed
    • you didn't include the clojure dependency [1]
  • :gen-class needs AOT - as Sanchayan pointed out
    • see [2]

project.clj

(defproject WaterTimer "0.0.1"
  :description "A timer that reminds you to drink water"
  :dependencies [[org.clojure/clojure "1.8.0"]] ;; <- [1]
  :main tone-producer    
  :aot [tone-producer])  ;; <- [2]

src/tone_producer.clj - USE '_' instead of '-' in the filename

(ns tone-producer
  (:import [javax.sound.midi MidiSystem
                             Synthesizer
                             MidiChannel])
  (:gen-class))

(defn -main [& args]
  (println "Test!"))

Result:

$ lein uberjar
Compiling tone-producer
Compiling tone-producer
Created .../watertimer/target/WaterTimer-0.0.1.jar
Created .../watertimer/target/WaterTimer-0.0.1-standalone.jar
$ java -jar target/WaterTimer-0.0.1-standalone.jar 
Test!

Generally I'd recommend to init a project with lein new <name> via command line and the import it into Cursive/Other IDE of choice.