Support compiled `.class` files as inputs
Is your feature request related to a problem? Please describe.
▶ scala-cli compile Main.scala -d compilation_output
To add .class files to the classpath, one currently has to do it the scalac way, by passing a directory with the compiled classes.
▶ scala-cli run --classpath compilation_output
Hello
It'd be convenient to be able to skip the --classpath option and pass .class straight up as an input.
Describe the solution you'd like Add support like:
▶ scala-cli Main.class Main$.class
Hello
working on this at the Tooling Spree with @MaciejG604 . iirc it's my first time in this codebase
The JVM does not support adding individual .class files to the classpath, so scala-cli will have to make a directory, copy the .class files there, and add that directory to the classpath.
Because we can't add the .class files to the classpath directly, this is probably a bit harder than anticipated...
We discussed two possible implementation strategies:
- somehow hijack the
extraClassPathmechanism in input processing - initially, during input processing, treat the
.classfiles almost as if they were.scalafiles, but before we actually invoke Bloop to do the compilation, insert a step where.classfiles are copied to a new directory, then we add that tofullClassPathinBuild.scala
we are currently exploring option 2
we spent much of the spree time just understanding the code and discussing approaches
but we did get partway through a rough initial implementation; we have code (not quite working yet) that copies the .class files to a new directory. next step would be to pass that directory to Bloop
for testing, we didn't write a test case yet, we're testing manually, which is fine actually. we have a sample .class file:
~/tmp/20250130 % cat J.java
public class J {
public static void main(String[] argv) {
System.out.println("hello world");
}
}
~/tmp/20250130 % javac J.java
and then in the scala-cli repo dir we do ./mill -i scala /Users/tisue/tmp/20250130/J.class
and tree ~/tmp/20250130/.scala-build shows the inputClasses-TODO having been created, but we aren't seeing the .class files showing up yet, maybe just some silly mistake in how we're using os-lib?
wip branch: https://github.com/SethTisue/scala-cli/commits/issue-1642/
we put "TODO" in the directory name we're using to indicate that there's an unresolved design question of where under .scala-build this stuff would more properly go
@MaciejG604 points out that we're currently assuming Bloop will be invoked, but we'll also need to consider what happens under --server=false
Did some more looking around the problematic bits, I think we can create the inputClasses directory during ScalaCompiler.prepareProject method.
I'd place the directory like we did in https://github.com/VirtusLab/scala-cli/pull/2584 at path projectRootDir(inputs.workspace, inputs.projectName) / Constants.inputClassesDirectoryName.
The directory should always be removed (if exists) and when needed it should be created.
If the Project instance created in Build.buildProject contains the path to the inputsClasses directory we should be fine with both bloop and server=false.
When it comes to tests I think the easiest would be an integration test like in CompileTestDefinitions. And maybe a test in BuildTests for checking the classpath like in "No stubs JAR at runtime".
One more thing to consider - ElementsUtils.singleFilesFromDirectory should probably also be updated.
Hope that's it 😄
Thank you @SethTisue for taking part in our Tooling Spree and helping us out!
Is this only useful for classfiles in the empty package? If the classfiles are in some package, don't we have to worry about the directory structure?
I often continue work on a spree PR after the spree has ended, but I think I will not return to this one. I enjoyed working it on it for the duration of a spree, but I don't think the feature has all that much value, especially since it's not very easy to implement.