Debug long compile times in Scala and SBT - scala

In my Scala/SBT project, I have one file that takes up to 5(!) minutes to compile. All the other ones can compile in a few seconds. This makes development pretty painful.
I'm sure that I'm abusing some Scala constructs, but I have no idea how to go about debugging it. How does one debug long compile times in Scala?
I'm using Scala 2.9.2 and SBT 0.11.2

You can try the following Scala compiler options:
-Ystatistics Print compiler statistics
Find a phase that takes the most time. Then, try those:
-Xprint:<phase> Print out program after or "all"
-Yshow-trees Show detailed trees when used in connection with -print:phase
-Ydebug Output debugging messages
-Ypmat-debug Trace all pattern matcher activity.
To enable these settings directly from the sbt console, you can use set scalacOptions in ThisBuild += "-Ystatistics", or for more than one, set scalacOptions in ThisBuild ++= Seq("-Yshow-trees", "-Ydebug")

Related

Profile Scala3 compiler

We have one Scala3 project where we use macros. We use Visual Studio Code with Metals plugin.
sbt clean compile
tooks more then 20 minutes. Is there any way to profile Scala3
compiler to figure out where that time goes?
You can set the compilerflag "-Vprofile" in your build.sbt.
scalacOptions += "-Vprofile"
It will output the complexity of your files. At least, it will give you a hint, where a lot of compile time will be spend.
Maybe this will be interesting for you as well:
Scala Sbt - Measure task time for subprojects

Real SBT Classpath at Runtime

I have some test cases that need to look at the classpath to extract the paths of some files/directories in there. This works fine in the IDE.
The problem is that, when running SBT test, Properties.javaClassPath gives me /usr/share/sbt-launcher-packaging/bin/sbt-launch.jar.
The classpath is fine when I run show test:dependency-classpath. Is there a way to obtain that information from inside the running Scala/Java program? Or is there a way to toss it into a system property or environment variable?
By default the tests are run inside of the SBT process, so the classpath will look like it did when you started sbt (I guess sbt does some trixery to dynamicly load the classes for the tests, not sure). One way to do what you want is to run your tests in a forked jvm, that way sbt will start a new jvm to run the test suite and that should have the expected class path:
fork in Test := true
I have been working on understanding how the EmbeddedCassandra works in the spark-cassandra-connector project which uses the classpath to start up and control a Cassandra instance. Here is a line from their configuration that gets the correct classpath.
(compile in IntegrationTest) <<= (compile in Test, compile in IntegrationTest) map { (_, c) => c }
The entire source can be found here: https://github.com/datastax/spark-cassandra-connector/blob/master/project/Settings.scala
Information on the <<= operator can be found here: http://www.scala-sbt.org/0.12.2/docs/Getting-Started/More-About-Settings.html#computing-a-value-based-on-other-keys-values. I'm aware that this is not the current version of sbt, but the definition still holds.

How to make SBT not reporting compilation warnings for generated code?

I generate code with the scalaxb-sbt plugin that, when compiled, generates a good number of warning messages. Is there any way to hide compilation warnings for generated code or by package?
The silencer compiler plugin allows to suppress compiler warnings. It supports filtering out files by path. This will filter out all generated files from warnings:
scalacOptions += "-P:silencer:pathFilters=src_managed"
For Scala 2.12.13+ or 2.13.2+
Recent versions of the Scala compiler integrate the silencer plugin, see configurable warnings.
So now you don't need any plugin, just add the following line to build.sbt:
ThisBuild / scalacOptions += "-Wconf:src=src_managed/.*:silent"
Using this option will suppress warnings for generated code that lives under a directory called src_managed anywhere in your source tree.
This solved my problem with code generated by zio-grpc, where the compiler emitted warnings like parameter value evidence$3 in method live is never used (adding this info only for better searchability).
In your sbt console you could try the following:
set logLevel in compile := Level.Error or eventually set logLevel in sourceGenerators := Level.Error
and experiment with different settings. Once you are happy you could apply this setting in your build.sbt.
More detailed information can be found in the sbt documentation: http://www.scala-sbt.org/release/docs/Howto/logging.html
I found that I needed to do set logLevel in Compile := Level.Error in my sbt console session in order for this to work. This is with a capital C in Compile. This is with sbt version 0.13.11. This is also to turn all warnings off, though.
Put the code in a subproject, and set scalacOptions differently in that project? Whether this will work depends on whether the support even exists in scalac for suppressing the particular kind of warning you are getting. See for example https://issues.scala-lang.org/browse/SI-1781 . What kind of warnings are you needing to suppress exactly? Certain warnings like unchecked warnings can be suppressed with e.g. #unchecked without having to do the subproject thing.

SBT Broken Pipe

I've been avoiding using SBT since the support in intellij for maven has always been far superior, plus I don't see much advantage in SBT; but I figure why fight the masses.
So one of my open source projects I've converted over to SBT. Now when I run tests (approx 1000 test cases), I get OOMs. Ok so I've tried
fork in Test := true
javaOptions in Test ++= Seq("-Xmx2048m", "-XX:MaxPermSize=512m")
Ok so my OOMs go away but now I get
sbt.ForkMain$Run$RunAborted: java.net.SocketException: Broken pipe
at sbt.ForkMain$Run.write(ForkMain.java:114)
at sbt.ForkMain$Run$1.info(ForkMain.java:132)
Seems to be in different places each time.
These tests all pass if I'm building via maven (scala test maven plugin).
Help me Obi-wan or SBT lovers.
Edit: Adding env details
sbt 0.12.4
java 7.25
scala 2.10.2

how to compile single file in sbt

I'm doing some refactoring that made compiler temporally give errors in several files. I'd like to work with them one by one (starting with common dependencies) and need some tool to check if modification is correct.
sbt compile is inconvenient because it gives too many errors and spends much time for compiling things that have no good.
I'm searching for a way to compile single file with sbt or a method for extracting sbt side libraries definition to pass them to a normal scalac compiler
There was a similar topic: How to compile just some files with sbt? that turned out to be source code error discussion rather that sbt functionality disclosure.
You could add the following line to build.sbt:
sources in Compile <<= (sources in Compile).map(_ filter(_.name == "Particular.scala"))
Then fix Particular.scala, then edit build.sbt and put the name of the next source file. If you keep the sbt console open, reload will re-read the .sbt file after you modify it.
I just wanted to mention here that I came across sbt-compile-quick-plugin (https://github.com/etsy/sbt-compile-quick-plugin). It does what it says on the tin, just add addSbtPlugin("com.etsy" % "sbt-compile-quick-plugin" % "1.3.0") to your project/plugins.sbt, then you can just start up sbt and run compileQuick /path/to/your/file