Question

I'm trying to compile Scala files programmatically by using an instance of Global.Run:

val settings = new Settings                 
val reporter = new ConsoleReporter(settings)
val compiler = new Global(settings, reporter)
val run = new compiler.Run // MissingRequirementError
run compile List(path)

Unfortunately I get a MissingRequirementError saying:

object scala.runtime in compiler mirror not found

So my question is how can I compile a file programmatically by using the Run class, or what am I doing wrong here?

I tried to figure out whether I could change the settings in order to get it work. Actually I need a list of classes that are in the Scala file at path, not necessarily a fully runnable output. It would therefore be fine if symbols remained unresolved (if I could run a subset of the compiler phases).

I also at Writing Scala Compiler Plugins, but if I can run it by instanciating a Compiler Run object, I'd prefer this solution. I also stumbled across Is the Scala compiler reentrant? (similar code, different question), which makes me think it might work the way I'm thinking of.

Edit 1: Added Scala JARs to the toolcp (just sample code with absolute path!)

According to a comment I adapted scalac.bat's classpath population script to my Scala code:

// scalac.bat
// if "%_TOOL_CLASSPATH%"=="" (
//   for %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f"
//   for /d %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f"
// )
new File("C:\\Program Files\\scala\\lib").listFiles.foreach(f => {
  settings.classpath.append(f.getAbsolutePath)
  settings.toolcp.append(f.getAbsolutePath)
})
Was it helpful?

Solution

I got it running, by using bootclasspath instead of toolcp (thanks to pedrofurla's hint):

val settings = new Settings
new File("C:\\Program Files\\scala\\lib").listFiles.foreach(f => {
  settings.classpath.append(f.getAbsolutePath)
  settings.bootclasspath.append(f.getAbsolutePath)
})

private val reporter = new ConsoleReporter(settings)
private val compiler = new Global(settings, reporter)

val run = new compiler.Run
run compile List(path)

The compiler attempts to compile the files now. However, this seems not to be exactly what scalac.bat does. It starts it with -cp, which is the normal classpath, whereas bootclasspath is passed with -bootclasspath on the console, as visible in StandardScalaSettings trait:

val bootclasspath = PathSetting ("-bootclasspath", "Override location of bootstrap class files.", Defaults.scalaBootClassPath)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top