-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix executable jars #13263
Fix executable jars #13263
Conversation
val mainClass = Option.when(!ctx.settings.XmainClass.isDefault)(ctx.settings.XmainClass.value).orElse { | ||
val _mainClassesBuffer = new mutable.HashSet[String] | ||
units.map { unit => | ||
unit.tpdTree.foreachSubTree { tree => | ||
val sym = tree.symbol | ||
import dotty.tools.dotc.core.NameOps.stripModuleClassSuffix | ||
val name = sym.fullName.stripModuleClassSuffix.toString | ||
if (sym.isStatic && !sym.is(Flags.Trait) && ctx.platform.hasMainMethod(sym)) { | ||
// If sym is an object, all main methods count, otherwise only @static ones count. | ||
_mainClassesBuffer += name | ||
} | ||
} | ||
} | ||
_mainClassesBuffer.toList.match | ||
case List(mainClass) => | ||
Some(mainClass) | ||
case Nil => | ||
report.warning("No Main-Class designated or discovered.") | ||
None | ||
case mcs => | ||
report.warning(s"No Main-Class due to multiple entry points:\n ${mcs.mkString("\n ")}") | ||
None | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is copied from compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala
I was thinking whether we could extract it for reuse rather than copy-paste, yet I wasn't sure where should I place it, maybe somewhere under dotty.tools.dotc.util
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please feel free to extract any code for reuse yes, doesn't matter too much where it ends up :). However, having to fully traverse every single compilation unit just to get main method names out is going to be fairly expensive and should be avoided, especially for information that we should already know. Maybe ExtractAPI (or some other phase which is always run if we want this to work even outside of sbt) should collect this information and store it in the Context. In fact, we used to have a phase which was supposed to do that but I deleted it because it was dead code: 3ebf919
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the advice, I will look into that :D
What is the correct way to update such context then or to pass fresh-cloned context with the updated state to the next phases? |
You can use |
I've seen |
…hem via GenBCode callback
@smarter could you take a final look and give approve if everything is OK :) |
* Small phase to be run to collect main classes and store them in the context. | ||
* The general rule to run this phase is either: | ||
* - The output of compilation is JarArchive and there is no `-Xmain-class` defined | ||
* - The compiler is run from sbt and is forced by flags forcing `ExtractorAPI` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this should be removed along with any code related to sbt in this phase since it no longer occurs before ExtractAPI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
32931bb
to
9cde003
Compare
Coming back with fixes for the compiler to produce runnable jars.
@som-snytt, you can play with the compiler now, for example, you can try these commands
Unfortunately, there is some hacking:
JarArchive
which sets up a new file system for writing files, then we write to it directly both bytecode and tasty files. JDK gives an interface calledJarOutputStream
which is convenient to produce Jar files and takes care of the creation of the manifest file, but with our current approach, it's hard to determine the manifest properties. We would have to store these files temporarily somewhere else then write them all usingJarOutputStream
(scala 2 has this pipeline afaik).JarInputStream
, when we try to run this jar usingjava -jar ...
it would start normally, even though MANIFEST is at the end of the archive.Thigs to reconsider:
java -jar ...
command (running frombin/scala
provides stdlib by default, so it is not problem for most of the simple scripts).