`run` task does not support `JEP 512: Compact Source Files and Instance Main Methods`
https://openjdk.org/jeps/445
Step
https://github.com/xuwei-k/sbt-JEP-445/commit/e2e6293aa4bc84a3ab506b67328786f88e011a7b
install JDK 21
A.java
void main() {
System.out.println("hello");
}
build.sbt
javacOptions ++= Seq(
"-Xlint:preview",
"--enable-preview",
"--release",
scala.util.Properties.javaSpecVersion
)
run / fork := true
run / javaOptions ++= Seq("--enable-preview")
scalaVersion := "3.3.1"
project/build.properties
sbt.version=1.9.6
sbt -J--enable-preview run
[error] java.lang.RuntimeException: No main class detected.
[error] at scala.sys.package$.error(package.scala:30)
expect
print hello
I think we use Zinc to detect main. Does JEP 445 generate A.class? If so what information can we get out of that using Zinc?
I've never liked that Scala tools are fussy about main.
$ scala hello-instance.scala
hello-instance.scala:11: warning: not a valid main method for Main,
because main methods must have the exact signature `(Array[String]): Unit`, though Scala runners will forgive a non-Unit result.
To define an entry point, please define the main method as:
def main(args: Array[String]): Unit
def main(args: Array[String]): Int = { println("hi!"); 42 }
^
hi!
It requires the args and will not inspect a class for an instance method.
@som-snytt
per https://openjdk.org/jeps/445#A-flexible-launch-protocol, JDK 21 relaxes the main constraints in three different ways:
- doesn't have to be public
- doesn't need
Array[String]parameter - doesn't have to be static method
This is serious relaxation, but it doesn't mention anything about being able to return Int, which I'd argue is a good thing because otherwise the user might expect that 42 would be the exit code
To a potential contributor:
Relevant code in Zinc is here: https://github.com/sbt/zinc/blob/a09cfdfc572a362d9deccc07256a4dffec5f27f9/internal/compiler-bridge/src/main/scala/xsbt/ExtractAPI.scala#L773-L775
if (sym.isStatic && defType == DefinitionType.Module && definitions.hasJavaMainMethod(sym)) {
_mainClasses += name
}
It might be tricky to implement https://openjdk.org/jeps/445#A-flexible-launch-protocol because it's worded like
- If a launched class contains no
staticmainmethod with aString[]parameter but does contain astaticmainmethod with no parameters, then invoke that method.
https://github.com/scala/scala/blob/2.13.x/src/sbt-bridge/scala/tools/xsbt/ExtractAPI.scala#L777
I don't know if the target audience of beginners have expectations, but I would like any non-Unit result to be printed, please.
Also if I'm running under sbt or REPL, don't exit the JVM.
- reported another issue https://github.com/scala/bug/issues/12878
Also note that you can supply mainClass manually.
Compile / run / mainClass := Some("A")
and that would work:
$ sbt -J--enable-preview run
[info] welcome to sbt 1.9.6 (Azul Systems, Inc. Java 21)
[info] loading global plugins from /Users/xxx/.sbt/1.0/plugins
[info] loading project definition from /private/tmp/jdk21/project
[info] loading settings for project jdk21 from build.sbt ...
[info] set current project to jdk21 (in build file:/private/tmp/jdk21/)
[info] running (fork) A
[info] hello
so maybe we can say that sbt works as expected, and the perk of using genuine Scala is you get automatic main detection.
To a potential contributor: relevant code in Zinc is here:
another Relevant code
https://github.com/sbt/sbt/blob/586e0a752cd5d0f0335deaa910c4355e0e0a0e56/run/src/main/scala/sbt/Run.scala#L160-L171