SBT使用项目定义的生成器生成代码 [英] SBT generate code using project defined generator

查看:68
本文介绍了SBT使用项目定义的生成器生成代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'd like to compile a project which contains a java source generator and then compile the generated code within a single project. I.e: compile Generator.scala, run Generator.generate(outputDir), compile outputDir, package into a jar. I'm trying this:

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

但是sbt抱怨

[error] Build.scala:1: object example is not a member of package org
[error] import org.example.Generator

基本上,sbt在编译的项目中看不到Generator。
是否可以通过sbt用我的方式完成?

Basically, sbt doesn't see Generator defined in the project it compiles. Is it possible to do it my way with sbt?

推荐答案

所以,在对此进行了一些探讨之后,我提出了解决方案。首先,您需要将您的项目分为两个子项目。 gen 具有包含生成器代码的所有源。 使用取决于 gen 并使用生成器。

So, after digging on this a bit, I have come up with a solution. First, you need to break your project into two sub projects. gen has all the source that includes your generator code. use depends on gen and uses the generator.

    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
      }
    }

在这种情况下,我正在生成.java文件,所以我将 javaSource 传递给了发电机。

In this case, I was generating .java files so I passed in javaSource to the generator.

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

It is important to not that when using sourceGenerators as we are here, the executed task must return a Seq[File] of all the files that were generated so that sbt can manage them. In this implementation, our generator outputs the full path file names to standard out and we save them to a temporary file.

与Scala和SBT一样,您可以做任何事情,只需要深入研究即可。

As with all things Scala and surely SBT, you can do anything, just need to dig into it.

这篇关于SBT使用项目定义的生成器生成代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆