scala-cli icon indicating copy to clipboard operation
scala-cli copied to clipboard

Support compiled `.class` files as inputs

Open Gedochao opened this issue 3 years ago • 6 comments

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

Gedochao avatar Dec 05 '22 14:12 Gedochao

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.

SethTisue avatar Jan 30 '25 16:01 SethTisue

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:

  1. somehow hijack the extraClassPath mechanism in input processing
  2. initially, during input processing, treat the .class files almost as if they were .scala files, but before we actually invoke Bloop to do the compilation, insert a step where .class files are copied to a new directory, then we add that to fullClassPath in Build.scala

we are currently exploring option 2

SethTisue avatar Jan 30 '25 17:01 SethTisue

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

SethTisue avatar Jan 30 '25 17:01 SethTisue

@MaciejG604 points out that we're currently assuming Bloop will be invoked, but we'll also need to consider what happens under --server=false

SethTisue avatar Jan 30 '25 17:01 SethTisue

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!

MaciejG604 avatar Jan 30 '25 21:01 MaciejG604

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.

SethTisue avatar Mar 03 '25 23:03 SethTisue