【问题标题】:Using macro-paradise and cross-compiling with 2.12/2.13使用宏天堂并与 2.12/2.13 交叉编译
【发布时间】:2021-07-13 17:05:18
【问题描述】:

自 Scala 2.13 起,macro-paradise 已内联在编译器中,并可通过编译器标志获得:

Compile / scalacOptions += "-Ymacro-annotations"

作为参考,在之前的 Scala 版本中,macro-paradise 可以通过编译器插件获得:

addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)

在针对 Scala 2.12 和 2.13 的构建中,根据 Scala 版本的值有条件地添加第一个设置或第二个设置的规范方法是什么?

我想写下面的,但它不起作用:

CrossVersion.partialVersion(scalaVersion.value) match {
  case Some((2, n)) if n >= 13 => Compile / scalacOptions += "-Ymacro-annotations"
  case _ => addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
}

它失败并出现以下错误:

error: `value` can only be used within a task or setting macro, such as :=, +=, ++=, Def.task, or Def.setting.
      CrossVersion.partialVersion(scalaVersion.value) match {
                                               ^

与此同时,我可以使用以下解决方法,但我希望支持更简单的解决方案:

Compile / scalacOptions ++= {
  CrossVersion.partialVersion(scalaVersion.value) match {
    case Some((2, n)) if n >= 13 => "-Ymacro-annotations" :: Nil
    case _ => Nil
  }
}

libraryDependencies ++= {
  CrossVersion.partialVersion(scalaVersion.value) match {
    case Some((2, n)) if n >= 13 => Nil
    case _ => compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full) :: Nil
  }
}

【问题讨论】:

    标签: sbt


    【解决方案1】:

    如果你想写

    CrossVersion.partialVersion(scalaVersion.value) match {
      case Some((2, n)) if n >= 13 => Compile / scalacOptions += "-Ymacro-annotations"
      case _ => addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)
    }
    

    一个选项是像这样定义SBT custom command

    def compileWithMacroParadise: Command = Command.command("compileWithMacroParadise") { state =>
      import Project._
      val extractedState = extract(state)
      val stateWithMacroParadise = CrossVersion.partialVersion(extractedState.get(scalaVersion)) match {
        case Some((2, n)) if n >= 13 => extractedState.appendWithSession(Seq(Compile / scalacOptions += "-Ymacro-annotations"), state)
        case _ => extractedState.appendWithSession(addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full), state)
      }
      val (stateAfterCompileWithMacroParadise, _) = extract(stateWithMacroParadise).runTask(Compile / compile, stateWithMacroParadise)
      stateAfterCompileWithMacroParadise
    }
    
    commands ++= Seq(compileWithMacroParadise),
    addCommandAlias("compile", "compileWithMacroParadise")
    

    sbt compile 现在应该在运行 compile 任务之前对构建状态 (stateWithMacroParadise) 进行适当的修改。

    【讨论】:

      【解决方案2】:

      完整的工作示例,将此代码添加到您的 project 目录中的 Compiler.scala 文件中:

      import sbt._
      import sbt.Keys._
      
      object Compiler extends AutoPlugin {
        override def trigger = allRequirements
      
        override def projectSettings: Seq[Def.Setting[_]] =
          Seq(
            libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match {
              case Some((2, x)) if x < 13 =>
                Seq(
                  compilerPlugin(("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)),
                  "org.scala-lang.modules" %% "scala-collection-compat" % "2.1.6"
                )
              case _ => Nil
            }),
            Compile / scalacOptions ++= (CrossVersion.partialVersion(scalaVersion.value) match {
              case Some((2, x)) if x >= 13 =>
                Seq("-Ymacro-annotations")
              case _ => Nil
            })
          )
      
      }
      

      请注意,你必须使用projectSettingsbuildSettings 将不起作用

      "scala-collection-compat" 依赖项是您在交叉编译 2.12 和 2.13 时通常需要的另一个依赖项。它让你做

      import scala.jdk.CollectionConverters._
      

      而不是使用已弃用的scala.collection.JavaConverters

      【讨论】:

      • 这应该是公认的解决方案!像魅力一样工作:)
      猜你喜欢
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2016-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-13
      相关资源
      最近更新 更多