SBT generate code using project defined generator

后端 未结 2 2063
青春惊慌失措
青春惊慌失措 2020-12-10 03:24

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 Generato

2条回答
  •  不知归路
    2020-12-10 03:41

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

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

    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.

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

提交回复
热议问题