"scala.runtime в зеркале компилятора не найден", но работает при запуске с -Xbootclasspath/p: scala -library.jar

Я пытаюсь запустить приложение Scala, упакованное как JAR (включая зависимости), но это не удастся, пока библиотека Scala не будет добавлена ​​с помощью параметра -Xbootclasspath/p.

Сбой вызова:

java -jar /path/to/target/scala-2.10/application-assembly-1.0.jar

После того, как приложение выполнило какой-либо намеченный вывод, консоль показывает:

Исключение в потоке "main" scala.reflect.internal.MissingRequirementError: object scala.runtime в зеркале компилятора не найден.         в scala.reflect.internal.MissingRequirementError $.signal(MissingRequirementError.scala: 16)         в scala.reflect.internal.MissingRequirementError $.notFound(MissingRequirementError.scala: 17)         на scala.reflect.internal.Mirrors $RootsBase.getModuleOrClass(Зеркала .scala: 48)         в scala.reflect.internal.Mirrors $RootsBase.getModuleOrClass(Mirrors.scala: 40)         в scala.reflect.internal.Mirrors $RootsBase.getModuleOrClass(Mirrors.scala: 61)         в scala.reflect.internal.Mirrors $RootsBase.getPackage(Зеркала .scala: 172)         в scala.reflect.internal.Mirrors $RootsBase.getRequiredPackage(Зеркала .scala: 175)         at scala.reflect.internal.Definitions $ОпределенияClass.RuntimePackage $lzycompute (Определения .scala: 181)         at scala.reflect.internal.Definitions $DefinitionsClass.RuntimePackage(Definitions.scala: 181)         at scala.reflect.internal.Definitions $ОпределенияClass.RuntimePackageClass $lzycompute (Определения .scala: 182)         at scala.reflect.internal.Definitions $DefinitionsClass.RuntimePackageClass(Определения .scala: 182)         at scala.reflect.internal.Definitions $ОпределенияClass.AnnotationDefaultAttr $lzycompute (Определения .scala: 1015)         at scala.reflect.internal.Definitions $DefinitionsClass.AnnotationDefaultAttr(Определения .scala: 1014)         at scala.reflect.internal.Definitions $ОпределенияClass.syntheticCoreClasses $lzycompute (Определения .scala: 1144)         at scala.reflect.internal.Definitions $DefinitionsClass.syntheticCoreClasses(Definitions.scala: 1143)         at scala.reflect.internal.Definitions $DefinitionsClass.symbolsNotPresentInBytecode $lzycompute (Определения .scala: 1187)         at scala.reflect.internal.Definitions $DefinitionsClass.symbolsNotPresentInBytecode(Definitions.scala: 1187)         at scala.reflect.internal.Definitions $ОпределенияClass.init(Определения .scala: 1252)         at scala.tools.nsc.Global $Run. (Global.scala: 1290)         at extract.ScalaExtractor $Компилятор $2 $. (ScalaExtractor.scala: 24)

Рабочий вызов:

java -Xbootclasspath/p:/path/to/home/.sbt/boot/scala-2.10.2/lib/scala-library.jar -jar /path/to/target/scala-2.10/application-assembly-1.0.jar

Странная вещь в том, что application-assembly-1.0.jar был построен так, чтобы он включал все зависимости, включая библиотеку Scala. Когда вы извлекаете JAR файл, можно проверить, что файлы классов в пакете scala.runtime были включены.

Создание файла JAR

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.1") был добавлен в project/plugins.sbt, и была вызвана цель assembly. Файл JAR с результатами около 25 МБ.

Построение JAR с помощью proguard показывает то же поведение во время выполнения, что и в файле сборки JAR.

Код приложения, который запускает MissingRequirementError

Некоторый код приложения работает нормально, и ранее описанное исключение запускается, как только выполняется new Run из следующего фрагмента.

import scala.reflect.internal.util.BatchSourceFile
import scala.reflect.io.AbstractFile
import scala.reflect.io.Path.jfile2path
import scala.tools.nsc.Global
import scala.tools.nsc.Settings
…
import scala.tools.nsc._
object Compiler extends Global(new Settings()) {
  new Run // This is line 24 from the stack trace!

  def parse(path: File) = {
    val code = AbstractFile.getFile(path)
    val bfs = new BatchSourceFile(code, code.toCharArray)
    val parser = new syntaxAnalyzer.UnitParser(new CompilationUnit(bfs))
    parser.smartParse()
  }
}
val ast = Compiler.parse(file)

Среди прочих, scala-library, scala-compiler и scala-reflect определяются как зависимости в build.sbt.

Для информации о curios/background

Цель приложения - помочь в локализации программ Java и Scala. Задача фрагмента кода выше - получить AST из файла Scala, чтобы найти там вызовы методов.

Вопросы

  • Учитывая, что библиотека Scala включена в файл JAR, почему необходимо вызвать JAR с помощью -Xbootclasspath/p:scala-library.jar?
  • Почему другие части приложения работают нормально, даже если scala.runtime сообщается как пропавший позже?

Ответ 1

Простой способ настройки параметров со знакомыми нажатиями клавиш:

  import scala.tools.nsc.Global
  import scala.tools.nsc.Settings
  def main(args: Array[String]) {
    val s = new Settings
    s processArgumentString "-usejavacp"
    val g = new Global(s)
    val r = new g.Run
  }

Это работает для вашего сценария.

Еще проще:

java -Dscala.usejavacp=true -jar ./scall.jar

Информация о бонусе, мне попалось сообщение о фиксации:

Пошли вперед и внедрили classpaths, как описано в scala -интерналы по теории, что в этот момент я должен знать, что я делает.

** ОБЪЯВЛЕНИЕ ОБЩЕСТВЕННОГО ОБСЛУЖИВАНИЯ **

Если ваш код любого типа перестает работать с этим фиксацией (большинство вероятно, что-то вроде ошибки "объект scala не найден" ), вы можете снова запустите его с помощью:

передача -usejavacp в командной строке

установить системное свойство "scala.usejavacp" в "true"

Любой из них предупредит scala, что вы хотите, чтобы приложение java classpath, который будет использоваться также с помощью scala.