Как запустить банку, сгенерированную пакетом (возможно, с другими банками под lib)?
Как запустить файл .jar
, который сгенерирован sbt package
?
Я создал очень простой пример с единственным источником .scala
:
package org.pack {
class ScalaParser(files: Array[String]) {
def doAll() = {
println("hello")
}
}
object Main {
def main(args: Array[String]): Unit = {
val sp = new ScalaParser(args)
sp.doAll()
}
}
}
После запуска
$ sbt
> compile
> package
.jar
создается в /target/scala-<version>
. Если я попытаюсь запустить его, он не даст этой ошибки:
$ java -jar package_2.9.2-0.1.jar
Exception in thread "main" java.lang.NoClassDefFoundError: scala/ScalaObject
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at org.pack.Main.main(Main.scala)
Caused by: java.lang.ClassNotFoundException: scala.ScalaObject
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 13 more
Обратите внимание, что внешние библиотеки не используются, а sbt compile run
работает нормально.
Я приложил весь проект, включая сгенерированный .jar в Dropbox.
Что действительно странно, так это то, что .jar
Manifest содержит правильный класс для загрузки, т.е. org.pack.Main
. Возможно, это вызвано чем-то другим.
Информация о системе
$ java -version
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1ubuntu1)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
$ scala -version
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
Дополнительный вопрос - что, если бы у меня был внешний .jar
в /lib
? Как я могу заверить, что они упакованы? Мне нужен один .jar
runnable (возможно) для каждого JVM.
Спасибо за помощь.
Ответы
Ответ 1
Вы можете использовать плагин sbt sbt-assembly:
sbt-assembly >= 0.12.0 с sbt >= 0.13.6
Поскольку sbt-assembly теперь является автоматическим плагином, достаточно добавить project/assembly.sbt в ваш проект sbt:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
sbt-assembly 0.11
Добавьте проект /assembly.sbt в свой проект sbt:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")
Добавьте также assembly.sbt:
import AssemblyKeys._ // put this at the top of the file
assemblySettings
Использование
Это даст вам еще одну команду sbt:
sbt assembly
который создает "живую банку" (которая включает все зависимости, включая библиотеки Scala).
Теперь вы можете запустить свою программу
java -cp.../package-assembly.jar
поэтому вам нужна только установка Java и "толстая банда".
Ответ 2
Попробуйте
scala package_2.9.2-0.1.jar
Обновление
Из Java команда будет выглядеть так:
java -cp $SCALA_HOME/lib/scala-library.jar -jar package_2.9.2-0.1.jar
Однако в пути к классу вам может понадобиться добавить дополнительные jar, например -cp "jar1.jar:jar2.jar"
Ответ 3
Для тех, кто не хочет строить живую банку, все зависимости будут загружены как часть успешного запуска sbt package
. Информация о маршруте хранится в файле в каталоге target
, который может быть передан в команду java
.
Пример:
sbt package
java -cp target/scala-2.11/yourproject.jar:$(cat target/streams/compile/dependencyClasspath/\$global/streams/export) Main