Hello everyone,
As some of you may know, I develop
Scala.js, a JavaScript backend for Scala. I would like to make sbt compatible with Scala.js so that it can be used as build tool for Scala.js projects.
I'd like to discuss here how that can be implemented.
I'm already saying that I do have a working prototype, but it seems to me to be more of a hack than a proper implementation. I've had an initial exploration with Jason last week, which eventually lead me to this prototype.
I would greatly appreciate any feedback on my approach.
The issue
The design of Scala.js is not to be a fork of scala/scala. Instead, it is a "regular" Scala program that uses scala-compiler.jar as a library. If it were, I would only have to specify a scalaHome, or a different published compiler version, but it's not.
That makes for a first issue: I have two jars for the compiler (scala-compiler.jar and scalajs-compiler.jar).
Moreover, Scala.js uses special Global instance, which is a subclass of scala.tools.nsc.Global. More precisely, Scala.js defines a trait scala.tools.nsc.scalajs.JSGlobal that is mixed in Global to create the Scala.js compiler instance.
That makes for the second issue: the compiler used by sbt to compile Scala.js programs must mix in the JSGlobal trait too.
I believe that a good, general solution to the support of Scala.js would provide the sbt user with:
1. A way to extend the classpath of the compiler with additional jars.
2. A way to specify the name of a top-level trait to be mixed in the Compiler instance used.
Ideally, these options should be editable as settings.
I will now describe the "solution" I implemented commit by commit (there are 5 of them), because they show the reasoning.
The solution provides the two features above, without breaking the rest of sbt. But I'm not sure it is the right, or nicest, way of providing these two features.
If you do not want to read it all, you can jump to "End result and conclusion".
A first hack that made it "work" and that shows what I need
Really, the useful part of that commit is to mixin JSGlobal with Compiler. All the other changes are hacks so that it compiles again (on my system, with hard-coded paths).
Mixin of JSGlobal at "runtime" with Scala reflection and its ToolBox
This removes the need to have scalajs-compiler.jar on the classpath while compiling the compiler interface (both precompiled and compiled on the fly). It is now only necessary to have it on the classpath when running the compiler.
It also takes a step towards configuring the name of the trait to be mixed in.
Set up the classpath in the compiler interface itself
is to have the compiler interface set up the appropriate classpath itself when creating its toolbox.
The main advantage here is to restore AnalyzingCompiler to its initial code.
Configure the trait name and jar path from build.sbt
With this, the code is now independent of my particular machine (at last). Moreover, the same codebase can be used not only for Scala.js, but for any other tool with the same design!
So now my 2 features are implemented.
Restore the good property of compiler interface to be compilable with 2.8 and 2.9
It does not make it work with Scala < 2.10; it just makes it compile. So a requirement to use the two big features is to use Scala 2.10+.
The main trick is to provide a dummy replacement for the Scala reflection API within the file. Careful abuse of import resolution order and precedence is used to have Scala 2.10 use the genuine reflection API, and Scala < 2.10 to refer to the dummies.
End result and conclusion
With that fork, I can use the following build.sbt file to build a Scala.js project:
name := "test-sbt-scalajs"
version := "0.1-SNAPSHOT"
scalaVersion := "2.10.1"
scalacOptions ++= Seq(
"-Dsbt.compile.interface.dynamiccompilertrait=scala.tools.nsc.scalajs.JSGlobal",
"-Dsbt.compile.interface.dynamiccompilerjar=/home/doeraene/.ivy2/local/ch.epfl.lamp/scala.js-compiler_2.10/0.1-SNAPSHOT/jars/scala.js-compiler_2.10.jar"
)
unmanagedJars in Compile += file("/home/doeraene/scalajs-library.jar")
There are still hard-coded paths in here, but that's another story, which I believe can be fixed just by tweaking the build.sbt file.
Asking for feedback
What are your feelings about this?
Do you agree with me that the 2 features are indeed the best "high-level requirement" to support Scala.js (and other tools with a similar architecture)?
What do you think about the way I implemented these two features? Would there be a better solution?
Thank you for reading until here!
Cheers,
Sébastien
You received this message because you are subscribed to the Google Groups "simple-build-tool" group.
To unsubscribe from this group and stop receiving emails from it, send an email to simple-build-tool+unsubscribe <at> googlegroups.com.
To post to this group, send email to simple-build-tool <at> googlegroups.com.
.