2016-02-23 4 views
1

Я нахожу, что новое приложение из лейн можно запустить как uberjar, но не как банку. Должно ли это работать так, или что-то не так с моей настройкой?Как я могу запустить банку из нового приложения lein без использования uberjar?

$ lein new app feedme 
$ cd feedme 

Lein uberjar работает просто отлично:

$ lein uberjar 
Compiling feedme.core 
Created .../feedme/target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar 
Created .../feedme/target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar 

$ java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar 
Hello, World! 

Lein банка не удается:

$ lein jar 
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 .../feedme/target/feedme-0.1.0-SNAPSHOT.jar 
$ java -jar target/feedme-0.1.0-SNAPSHOT.jar 
Error: Could not find or load main class feedme.core 

Там есть: генераторный класс директива в разделе нса core.clj, так что я м не знаю, в чем проблема:

$ cat src/feedme/core.clj 
(ns feedme.core 
    (:gen-class)) 

(defn -main 
    "I don't do a whole lot ... yet." 
    [& args] 
    (println "Hello, World!")) 

ответ

4

Lein jar только завершает ваш собственный код в банке, чтобы его можно было использовать другим проектом, например. Он не включает какие-либо из ваших зависимостей (которые будут объявлены в вашем pom.xml), включая сам clojure. Без действительного класса для запуска (например, clojure.main) он не может запустить ваш код. И следующей проблемой будут ваши требования, относящиеся к определениям в артефактах, которые не относятся к вашему пути к классам (если какая-то программа не загрузила ваш pom.xml и не знала, как выполнить эти зависимости).

3

Загляните в любую банку (они всего лишь zip-файлы) в файле MANIFEST.MF. Этот файл скажет вам основной класс. Поэтому, если вы убедитесь, что MANIFEST.MF попадает в ваш файл jar, он будет самозапускаемым. Файл jar содержит файлы .class и относится к другим файлам jar - поэтому он может составлять свой собственный путь к классам, пока доступны ссылки на файлы jar.

Я только что просмотрел несколько файлов jar. MANIFEST.MF находится в META-INF. Вот пример содержания:

Manifest-Version: 1.0 
Ant-Version: Apache Ant 1.8.3 
Created-By: 1.7.0_76-b13 (Oracle Corporation) 
Main-Class: com.cmts.client.applic.upgrader.UsersGUI 
Date-Created: 15/07/2015 02:23 AM 
Class-Path: ../lib/config-1.2.1.jar   
      ../lib/scala-library-2.11.5.jar      
      ../lib/org.springframework.beans-3.1.0.RC2.jar  
      ../lib/org.springframework.aop-3.1.0.RC2.jar 

Этот файл был создан Ant. Я не знаю, делает ли лейн то же самое. Но даже если этого нет, нет причин, по которым вы не можете поставить META-INF\MANIFEST.MF в банку. Тогда у вас будет самозапускаемый файл jar.

позже редактировать - LEIN манифеста пример:

:manifest {"Class-Path" "../lib/clojure-1.8.0.jar"} 
+0

А, это полезно знать. Когда вы говорите «self-runnable», я предполагаю, что это означает, что вы можете запускать его, как java -jar myapp.jar, а не как ./myapp.jar. – ijt

+0

Да 'java -jar myapp.jar' запускает основной класс - вот что я имел в виду под« self-runnable ». В зависимости от настройки вашей ОС двойной щелчок сделает это. И вся информация о classpath не обязательно должна быть там, поскольку информация cp, как и основной класс, указана в самом файле jar. –

2

Вы получаете Error: Could not find or load main class feedme.core, потому что банки не содержит feedme/core.class файл. Если вы запустите jar -tf target/feedme-0.1.0-SNAPSHOT.jar, вы увидите, что он вообще не содержит .class-файла. lein jar не компилирует исходники по умолчанию. Это предполагаемое поведение: Clojure компилирует код «на лету», если не требуется компиляция AOT. В случае компиляции uberjar AOT отправляется в файле project.clj через профиль {:uberjar {:aot :all}} (вы можете сделать небольшой эксперимент, изменив профиль uberjar на пустой {:uberjar {}}, тогда lein uberjar && java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar приведет к точно такой же ошибке).

Вы можете запустить lein with-profile uberjar jar, чтобы скомпилировать ваш код. Но если вы запустите java -jar target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar, вы получите еще одну ошибку: java.lang.NoClassDefFoundError: clojure/lang/IFn. Как указано noisemith lein jar не упаковывает никаких зависимостей, включая самого Clojure. Поэтому вы должны явно указать Clojure в пути к классам: java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar" feedme.core. Это напечатает Hello, World! (предполагая, что у вас есть Clojure 1.8 в вашем локальном репозитории Maven, вам может потребоваться сначала его загрузить или изменить путь/версию).

Без компиляции вы можете запускать jar, сгенерированный с помощью lein jar, с: java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/feedme-0.1.0-SNAPSHOT.jar" clojure.main --main feedme.core (снова ваш путь/версия банку Clojure может быть разным).