aboutsummaryrefslogtreecommitdiff
path: root/project
diff options
context:
space:
mode:
authorSébastien Doeraene <sjrdoeraene@gmail.com>2016-02-26 16:30:39 +0100
committerSébastien Doeraene <sjrdoeraene@gmail.com>2016-03-01 15:47:56 +0100
commitcd4004a82d9713bbb0b120aba83b3ed8fc9f1372 (patch)
tree309f090cb79fba02746b7b8a0109e171881d5d27 /project
parent0ebf36b394b00f3f432d8fdedeaa15e7d4df2b06 (diff)
downloaddotty-cd4004a82d9713bbb0b120aba83b3ed8fc9f1372.tar.gz
dotty-cd4004a82d9713bbb0b120aba83b3ed8fc9f1372.tar.bz2
dotty-cd4004a82d9713bbb0b120aba83b3ed8fc9f1372.zip
Initial infrastructure and hello world for the Scala.js back-end.
The Scala.js back-end can be enabled with the `-scalajs` command-line option. Currently, it adds one phase to the pipeline, which emits .sjsir files from trees. A sandbox project `sjsSandbox`, in `sandbox/scalajs/`, can be used to easily test Scala.js compilation. One can run the `main()` method of the `hello.world` object with > sjsSandbox/run The back-end only contains the bare mimimum to compile the hello world application in the sandbox. Anything else will blow up (for example, primitive method calls). It is a work-in-progress.
Diffstat (limited to 'project')
-rw-r--r--project/Build.scala151
-rw-r--r--project/plugins.sbt2
2 files changed, 153 insertions, 0 deletions
diff --git a/project/Build.scala b/project/Build.scala
index 66a380e96..4a22f3d82 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -4,6 +4,9 @@ import java.io.{ RandomAccessFile, File }
import java.nio.channels.FileLock
import scala.reflect.io.Path
+import org.scalajs.sbtplugin.ScalaJSPlugin
+import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
+
object DottyBuild extends Build {
val jenkinsMemLimit = List("-Xmx1300m")
@@ -33,6 +36,10 @@ object DottyBuild extends Build {
)
}
+ /** Enforce 2.11.5. Do not let it be upgraded by dependencies. */
+ private val overrideScalaVersionSetting =
+ ivyScala := ivyScala.value.map(_.copy(overrideScalaVersion = true))
+
lazy val `dotty-interfaces` = project.in(file("interfaces")).
settings(
// Do not append Scala versions to the generated artifacts
@@ -44,6 +51,8 @@ object DottyBuild extends Build {
lazy val dotty = project.in(file(".")).
dependsOn(`dotty-interfaces`).
settings(
+ overrideScalaVersionSetting,
+
// set sources to src/, tests to test/ and resources to resources/
scalaSource in Compile := baseDirectory.value / "src",
javaSource in Compile := baseDirectory.value / "src",
@@ -74,6 +83,8 @@ object DottyBuild extends Build {
"org.scala-lang.modules" %% "scala-partest" % "1.0.11" % "test",
"com.novocode" % "junit-interface" % "0.11" % "test",
"jline" % "jline" % "2.12"),
+ libraryDependencies +=
+ "org.scala-js" %% "scalajs-ir" % scalaJSVersion,
// enable improved incremental compilation algorithm
incOptions := incOptions.value.withNameHashing(true),
@@ -144,9 +155,54 @@ object DottyBuild extends Build {
addCommandAlias("partest-only-no-bootstrap", ";test:package;package; lockPartestFile;test:test-only dotc.tests;runPartestRunner")
)
+ /** A sandbox to play with the Scala.js back-end of dotty.
+ *
+ * This sandbox is compiled with dotty with support for Scala.js. It can be
+ * used like any regular Scala.js project. In particular, `fastOptJS` will
+ * produce a .js file, and `run` will run the JavaScript code with a JS VM.
+ *
+ * Simply running `dotty/run -scalajs` without this sandbox is not very
+ * useful, as that would not provide the linker and JS runners.
+ */
+ lazy val sjsSandbox = project.in(file("sandbox/scalajs")).
+ enablePlugins(ScalaJSPlugin).
+ settings(
+ overrideScalaVersionSetting,
+
+ /* Remove the Scala.js compiler plugin for scalac, and enable the
+ * Scala.js back-end of dotty instead.
+ */
+ libraryDependencies ~= { deps =>
+ deps.filterNot(_.name.startsWith("scalajs-compiler"))
+ },
+ scalacOptions += "-scalajs",
+
+ // The main class cannot be found automatically due to the empty inc.Analysis
+ mainClass in Compile := Some("hello.world"),
+
+ // While developing the Scala.js back-end, it is very useful to see the trees dotc gives us
+ scalacOptions += "-Xprint:labelDef",
+
+ /* Debug-friendly Scala.js optimizer options.
+ * In particular, typecheck the Scala.js IR found on the classpath.
+ */
+ scalaJSOptimizerOptions ~= {
+ _.withCheckScalaJSIR(true).withParallel(false)
+ }
+ ).
+ settings(compileWithDottySettings).
+ settings(inConfig(Compile)(Seq(
+ /* Make sure jsDependencyManifest runs after compile, otherwise compile
+ * might remove the entire directory afterwards.
+ */
+ jsDependencyManifest <<= jsDependencyManifest.dependsOn(compile)
+ )))
+
lazy val `dotty-bench` = project.in(file("bench")).
dependsOn(dotty % "compile->test").
settings(
+ overrideScalaVersionSetting,
+
baseDirectory in (Test,run) := (baseDirectory in dotty).value,
libraryDependencies ++= Seq("com.storm-enroute" %% "scalameter" % "0.6" % Test,
@@ -198,4 +254,99 @@ object DottyBuild extends Build {
})
case None => throw new RuntimeException("ERROR: sbt getJarPaths: ivyHome not defined")
}
+
+ // Compile with dotty
+ lazy val compileWithDottySettings = {
+ inConfig(Compile)(inTask(compile)(Defaults.runnerTask) ++ Seq(
+ // Compile with dotty
+ fork in compile := true,
+
+ compile := {
+ val inputs = (compileInputs in compile).value
+ import inputs.config._
+
+ val s = streams.value
+ val logger = s.log
+ val cacheDir = s.cacheDirectory
+
+ // Discover classpaths
+
+ def cpToString(cp: Seq[File]) =
+ cp.map(_.getAbsolutePath).mkString(java.io.File.pathSeparator)
+
+ val compilerCp = Attributed.data((fullClasspath in (dotty, Compile)).value)
+ val cpStr = cpToString(classpath ++ compilerCp)
+
+ // List all my dependencies (recompile if any of these changes)
+
+ val allMyDependencies = classpath filterNot (_ == classesDirectory) flatMap { cpFile =>
+ if (cpFile.isDirectory) (cpFile ** "*.class").get
+ else Seq(cpFile)
+ }
+
+ // Compile
+
+ val cachedCompile = FileFunction.cached(cacheDir / "compile",
+ FilesInfo.lastModified, FilesInfo.exists) { dependencies =>
+
+ logger.info(
+ "Compiling %d Scala sources to %s..." format (
+ sources.size, classesDirectory))
+
+ if (classesDirectory.exists)
+ IO.delete(classesDirectory)
+ IO.createDirectory(classesDirectory)
+
+ val sourcesArgs = sources.map(_.getAbsolutePath()).toList
+
+ /* run.run() below in doCompile() will emit a call to its
+ * logger.info("Running dotty.tools.dotc.Main [...]")
+ * which we do not want to see. We use this patched logger to
+ * filter out that particular message.
+ */
+ val patchedLogger = new Logger {
+ def log(level: Level.Value, message: => String) = {
+ val msg = message
+ if (level != Level.Info ||
+ !msg.startsWith("Running dotty.tools.dotc.Main"))
+ logger.log(level, msg)
+ }
+ def success(message: => String) = logger.success(message)
+ def trace(t: => Throwable) = logger.trace(t)
+ }
+
+ def doCompile(sourcesArgs: List[String]): Unit = {
+ val run = (runner in compile).value
+ run.run("dotty.tools.dotc.Main", compilerCp,
+ "-classpath" :: cpStr ::
+ "-d" :: classesDirectory.getAbsolutePath() ::
+ options ++:
+ sourcesArgs,
+ patchedLogger) foreach sys.error
+ }
+
+ // Work around the Windows limitation on command line length.
+ val isWindows =
+ System.getProperty("os.name").toLowerCase().indexOf("win") >= 0
+ if ((fork in compile).value && isWindows &&
+ (sourcesArgs.map(_.length).sum > 1536)) {
+ IO.withTemporaryFile("sourcesargs", ".txt") { sourceListFile =>
+ IO.writeLines(sourceListFile, sourcesArgs)
+ doCompile(List("@"+sourceListFile.getAbsolutePath()))
+ }
+ } else {
+ doCompile(sourcesArgs)
+ }
+
+ // Output is all files in classesDirectory
+ (classesDirectory ** AllPassFilter).get.toSet
+ }
+
+ cachedCompile((sources ++ allMyDependencies).toSet)
+
+ // We do not have dependency analysis when compiling externally
+ sbt.inc.Analysis.Empty
+ }
+ ))
+ }
}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index f9c0dbf1a..0c8b7737e 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -6,3 +6,5 @@
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0")
+
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.7")