如何在不使用 uberjar 的情况下从新鲜的 lein 应用程序运行罐子



我发现来自lein的新应用程序可以作为uberjar运行,但不能作为jar运行。它应该以这种方式工作,还是我的设置有问题?

$ 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 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 的 ns 部分中有一个 :gen-class 指令,所以我不确定问题是什么:

$ cat src/feedme/core.clj 
(ns feedme.core
  (:gen-class))
(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

Lein jar 只将您自己的代码包装在一个 jar 中,例如,它可以被另一个项目使用。它不包括您的任何依赖项(将在您的pom.xml中声明),包括clojure本身。没有要运行的有效类(例如。 clojure.main ),它无法运行您的代码。下一个问题是 require 语句,这些语句引用不在类路径上的工件中的定义(除非某个程序加载了您的pom.xml并且知道如何满足这些依赖项)。

查看任何 jar 内部(它们只是 zip 文件)的清单。MF 文件。该文件将告诉您主类。因此,如果您确定清单。MF 进入您的 jar 文件,它将是可自运行的。jar 文件包含.class文件并引用其他 jar 文件 - 因此只要引用的 jar 文件可访问,它就可以组成自己的类路径。

我刚刚查看了几个 jar 文件。 MANIFEST.MFMETA-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

这个是由蚂蚁创造的。我不知道莱因是否也做同样的事情。但即使没有,也没有理由不能把META-INFMANIFEST.MF放进罐子里。然后,您将拥有一个可自行运行的jar文件。

后期编辑 - LEIN 清单示例:

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

你会得到Error: Could not find or load main class feedme.core,因为jar不包含feedme/core.class文件。如果您运行jar -tf target/feedme-0.1.0-SNAPSHOT.jar您将看到它根本不包含任何.class文件。 默认情况下,lein jar 不会编译源代码。这是预期行为:除非请求AOT编译,否则Clojure会动态编译代码。在 uberjar 的情况下,通过 {:uberjar {:aot :all}} 配置文件在 project.clj 文件中请求 AOT 编译(您可以通过将 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 。正如noisesmith所指出的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 。这将打印你好,世界!(假设你在本地 Maven 存储库中有 Clojure 1.8,你可能需要先获取它或更改路径/版本)。

无需编译,您可以使用以下命令运行使用 lein jar 生成的 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 jar 路径/版本可能不同)。

最新更新