6

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.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
  • try re-naming main `-main` / or in your 2nd approch remove the `:main` from project.clj - EDIT: wait isn't there a `src//core.clj` normally - your project layout looks odd – birdspider Jul 12 '16 at 12:59
  • if I do `lein new watertimer` I get https://gist.github.com/birdspider/dcb987f881199f0a6721af4d8fd41a10 - maybe you can try to init the project that way. – birdspider Jul 12 '16 at 13:06
  • further your defproject is missing the clojure `:dependencies` (i.e. `:dependencies [[org.clojure/clojure "1.8.0"]]`) therefor you get the second `Error` – birdspider Jul 12 '16 at 13:18
  • @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 it – noisesmith Jul 12 '16 at 13:19

2 Answers2

4

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.

Sanchayan Maity
  • 637
  • 6
  • 19
4

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.

birdspider
  • 3,034
  • 1
  • 16
  • 25
  • Awesome, thanks, I'll test it in a sec. I created it manually because I don't have leiningen on the path, I only touched it for the first time this morning, and I don't even know where it's located on my drive. I'll need to get it set-up I guess. – Carcigenicate Jul 12 '16 at 15:04
  • Leiningen can't find the aforementioned `general-helpers`, and my break's over, so I'll have to test this later. `general-helpers` is located within a folder located in the same folder as "WaterTimer". How can I add that dependency to `project.clj`? – Carcigenicate Jul 12 '16 at 15:27
  • @Carcigenicate, I suspect your general-helpers ns it not `general_helpers.clj` in the file system (MIND THE `_ vs. -`), your source files CANNOT have a `-` in their name – birdspider Jul 12 '16 at 15:28
  • It uses an underscore. My use of a dash in the question was a typo. – Carcigenicate Jul 12 '16 at 15:30
  • @Carcigenicate, I think it would be a good idea if you provide a (possibly trimmed) output of the command-line commando `tree` of your project-root - so we can actually see where and how you files and foldes are structured. – birdspider Jul 12 '16 at 15:35
  • Since it's besides this question, I might just start a new question on including local dependencies. When I get a chance to test your suggestions, I'll remove the "require" from the code, and try making a jar. – Carcigenicate Jul 12 '16 at 17:09
  • Awesome, thanks. Works great. 1 problem down at least. – Carcigenicate Jul 12 '16 at 17:57
  • @Carcigenicate, note that if you create a lein project via Cursive, all it does is call `lein new` and then import that project. So you can do that and avoid setting up lein locally for now if you want to. – Colin Jul 12 '16 at 23:36
  • @Colin Oh thanks. For the past hour I've been manually creating projects :/. – Carcigenicate Jul 13 '16 at 00:22
  • Is it really necessary to compile `tone-producer` twice? And if not how do you avoid it? – Jacob Jan 18 '20 at 19:17