SBT使用项目定义的生成器生成代码

nau*_*nau 16 code-generation sbt

我想编译一个包含java源代码生成器的项目,然后在单个项目中编译生成的代码.即:编译Generator.scala,运行Generator.generate(outputDir),将outputDir,package编译成jar.我正在尝试这个:

sourceGenerators in Compile <+= sourceManaged in Compile map { out =>
    Generator.generate(out / "generated")
}
Run Code Online (Sandbox Code Playgroud)

但是sbt抱怨

[error] Build.scala:1: object example is not a member of package org
[error] import org.example.Generator
Run Code Online (Sandbox Code Playgroud)

基本上,sbt没有看到它编译的项目中定义的Generator.是不是可以用sbt的方式做到这一点?

Mar*_*rin 13

所以,在深入研究一下之后,我想出了一个解决方案.首先,您需要将项目分成两个子项目. gen拥有包含您的生成器代码的所有源代码. use依赖gen并使用发电机.

    import sbt._
    import Keys._
    import java.io.{ File ? JFile, FileOutputStream }

    object OverallBuild extends Build {

      lazy val root = Project(id = "overall", base = file(".")).aggregate(gen, use)

      lazy val gen = Project(id = "generate", base = file("gen"))

      val myCodeGenerator = TaskKey[Seq[File]]("mycode-generate", "Generate My Awesome Code")

      lazy val use = Project(id = "use", base = file("use"),
        settings = Defaults.defaultSettings ++ Seq(

          sourceGenerators in Compile <+= (myCodeGenerator in Compile),

          myCodeGenerator in Compile <<=
            (javaSource in Compile, dependencyClasspath in Runtime in gen) map {

              (javaSource, cp) ? runMyCodeGenerator(javaSource, cp.files)

            })).dependsOn(gen)

      def runMyCodeGenerator(javaSource: File, cp: Seq[File]): Seq[File] = {
        val mainClass = "com.yourcompany.myCodeGenerator"
        val tmp = JFile.createTempFile("sources", ".txt")
        val os = new FileOutputStream(tmp)

        try {
          val i = new Fork.ForkScala(mainClass).fork(None, Nil, cp,
            Seq(javaSource.toString),
            None,
            false,
            CustomOutput(os)).exitValue()

          if (i != 0) {
            error("Trouble with code generator")
          }
        } finally {
          os.close()
        }
        scala.io.Source.fromFile(tmp).getLines.map(f ? file(f)).toList
      }
    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我正在生成.java文件,所以我传入javaSource了生成器.

重要的是,当我们在这里使用sourceGenerators时,执行的任务必须返回生成Seq[File]的所有文件中的一个,以便sbt可以管理它们.在此实现中,我们的生成器将完整路径文件名输出到标准输出,并将它们保存到临时文件中.

就像Scala和SBT一样,你可以做任何事情,只需要深入研究它.