【问题标题】:Dynamic compilation with scala 2.12 - from sbt test使用 scala 2.12 进行动态编译 - 来自 sbt test
【发布时间】:2020-04-19 01:05:36
【问题描述】:

我想测试我编写的转换一些 scala 源代码的工具,我想检查转换后的代码是否从 sbt 测试编译(使用 scalatest)。

我想用我的源代码以编程方式调用一个字符串上的 scala 编译器(全部都在一个独立文件中)。

自最初的问题以来,我取得了一些进展。此代码适用于我的 IDE (IntelliJ),但不适用于 sbt test 会话

import java.io.File
import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.{GenericRunnerSettings, Global}

object Compilation {
  val settings = new GenericRunnerSettings(System.out.println _)
//  val sbtClasspath = System.getProperty("sbt-classpath")
//  val s = File.pathSeparator
//  val classPath = s".${s}$sbtClasspath"
//  settings.classpath.append(classPath)
  settings.usejavacp.value = true
  val global = new Global(settings)

  def compiles(code: String): Boolean = {
    val r = new global.Run
    r.compileSources(List(new BatchSourceFile("<partest>", code)))
    val errors = global.reporter.hasErrors
    if (errors) r.reporting.summarizeErrors()
    !errors
  }
}

这是我的build.sbt

name := "CodinGame-Scala-Kit"
version := "0.1.0"
scalaVersion := "2.12.2"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.12.2" % "test"

enablePlugins(JmhPlugin)

//val sbtcp = taskKey[Unit]("sbt-classpath")
//
//sbtcp := {
//  val files: Seq[File] = (fullClasspath in Compile).value.files
//  val sbtClasspath: String = files.map(x => x.getAbsolutePath).mkString(java.io.File.pathSeparator)
//  println("Set SBT classpath to 'sbt-classpath' environment variable")
//  println(sbtClasspath)
//  System.setProperty("sbt-classpath", sbtClasspath)
//}
//
//compile <<= (compile in Compile).dependsOn(sbtcp)

最初的错误是

scala.reflect.internal.MissingRequirementError: object scala.annotation.Annotation in compiler mirror not found.
[info]   at scala.reflect.internal.MissingRequirementError$.signal(MissingRequirementError.scala:17)
[info]   at scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:18)
[info]   at scala.reflect.internal.Mirrors$RootsBase.$anonfun$getModuleOrClass$4(Mirrors.scala:54)
[info]   at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:54)
[info]   at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:45)
[info]   at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:66)
[info]   at scala.reflect.internal.Mirrors$RootsBase.getClassByName(Mirrors.scala:101)
[info]   at scala.reflect.internal.Mirrors$RootsBase.getRequiredClass(Mirrors.scala:104)
[info]   at scala.reflect.internal.Mirrors$RootsBase.requiredClass(Mirrors.scala:107)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass.AnnotationClass$lzycompute(Definitions.scala:1141)

我在build.sbt 和Compilation 对象中添加了注释在this answer 之后的行。它在 IDE 中没有任何改变。

我现在在 sbt 测试中有这个错误(编译正确打印类路径):

 scala.reflect.internal.FatalError: class StringContext does not have a member f
[info]   at scala.reflect.internal.Definitions$DefinitionsClass.fatalMissingSymbol(Definitions.scala:1236)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass.$anonfun$getMember$1(Definitions.scala:1259)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass.getMember(Definitions.scala:1254)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass.getMemberMethod(Definitions.scala:1288)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass$RunDefinitions.StringContext_f$lzycompute(Definitions.scala:1477)
[info]   at scala.reflect.internal.Definitions$DefinitionsClass$RunDefinitions.StringContext_f(Definitions.scala:1477)
[info]   at scala.tools.reflect.FastTrack.$anonfun$fastTrackCache$1(FastTrack.scala:53)
[info]   at scala.reflect.internal.SymbolTable$perRunCaches$$anon$1.apply(SymbolTable.scala:395)
[info]   at scala.tools.reflect.FastTrack.contains(FastTrack.scala:20)
[info]   at scala.tools.nsc.typechecker.Namers$Namer.methodSig(Namers.scala:1388)

【问题讨论】:

  • 我现在正在使用最新的 sbt (0.13.15),这使得最后一个错误更简单。可以链接到这个类似的错误...github.com/scala/bug/issues/10058
  • 我看到了相反的问题。它适用于 sbt,但在 IntelliJ 中失败。
  • 重新加载项目似乎可以解决它。不确定是什么问题。

标签: scala dynamic compilation sbt scala-compiler


【解决方案1】:

第二种方法看起来与对我有用的方法相似,您显然在某处缺少依赖项。空的设置将不起作用。 要么更改设置 bootclasspath

或者简单地使用 settings.usejavacp.value = true

【讨论】:

    【解决方案2】:

    我终于找到了一种可靠的方法来编译任何字符串:

    import scala.reflect.runtime.currentMirror
    import scala.tools.reflect.ToolBox
    
    object Compiler {
    
      def compile[A](string: String): A = {
        val toolbox = currentMirror.mkToolBox()
        val tree    = toolbox.parse(string)
        toolbox.eval(tree).asInstanceOf[A]
      }
    }
    

    与

    libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.12.10"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-14
      • 2017-10-26
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      相关资源
      最近更新 更多