Search code examples
scalascala-2.10scala-compiler

MissingRequirementError when Compiling Scala code with Global.Run


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)
})

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)