8

As asked in this thread on the Scala mailing list, how can I create an embedded Scala REPL that inherits the classpath of the parent program? Suppose the parent Scala program is launched using scala -cp <classpath> ...; can <classpath> be accessed as a string and used to initialize the embedded REPL? (The Java classpath, available via System.getProperty("java.class.path"), appears to differ from the Scala classpath.)

Alternatively, perhaps the embedded Scala REPL can inherit or construct its ClassLoader from the parent process (Michael Dürig's ScalaDays 2010 talk might be relevant). Is this the recommended approach?

ziggystar
  • 28,410
  • 9
  • 72
  • 124
Kipton Barros
  • 21,002
  • 4
  • 67
  • 80
  • I've never before heard of an Scala interpreter. Where can I get it? – ziggystar Jun 26 '11 at 19:20
  • By interpreter I mean the Scala REPL. It comes with the Scala compiler. It's what you get when you execute the `scala` executable from the command line. This question is about embedding a REPL within a running Scala program. – Kipton Barros Jun 27 '11 at 04:20
  • I have edited your answer to reflect that you mean REPL. – ziggystar Jun 27 '11 at 07:10
  • @ziggystar The words interpreter and REPL are somewhat interchangeable. For example: http://www.scala-lang.org/node/2097 – Kipton Barros Jun 27 '11 at 20:04

3 Answers3

6

I'm trying to do the same thing, and I just found a way my out by Googling:

lazy val urls = java.lang.Thread.currentThread.getContextClassLoader match {
  case cl: java.net.URLClassLoader => cl.getURLs.toList
  case _ => error("classloader is not a URLClassLoader")
}
lazy val classpath = urls map {_.toString}

The above code gets you the classpath in current context.

settings.classpath.value = classpath.distinct.mkString(java.io.File.pathSeparator)

Put that into your settings.classpath and you should be able to fire up dispatch or whatever library you need.

Eugene Yokota
  • 94,654
  • 45
  • 215
  • 319
  • Thanks, this is useful. The workaround that I had settled on was to use the Java classpath environment variable (i.e. `$CLASSPATH`) instead of the Scala classpath. The Java classpath is inherited by the embedded interpreter, and then the "usejavacp" option works. – Kipton Barros Jun 26 '11 at 21:52
2

set the usejavacp property to true:

val settings = new scala.tools.nsc.Settings
settings.usejavacp.value = true
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • This technique does not seem to add the _Scala_ classpath to the newly created interpreter. As documented in `scala.tools.nsc.StandardScalaSettings.scala`, this option only includes `java.class.path` in classpath resolution. – Kipton Barros Nov 08 '10 at 21:41
  • Have a look at https://lampsvn.epfl.ch/trac/scala/wiki/Classpath and the related source code at http://lampsvn.epfl.ch/svn-repos/scala/scala-msil/trunk/src/compiler/scala/tools/util/PathResolver.scala These describe the current class path handling in quite some detail. – michid Nov 09 '10 at 09:19
  • I'm not sure how to use this information. Is there a way to access the instance of scala.tools.util.PathResolver in the currently executing program? If so, I can reuse its Settings object for the embedded interpreter I'm creating. – Kipton Barros Nov 10 '10 at 20:57
1

There does not seem to be an easy way to access the "Scala classpath" from within a running Scala program (in contrast, the "Java classpath" is available through the java.class.path system property). One would like to access, e.g., the field Calculated.userClasspath in the instance of scala.tools.PathResolver, but the latter does not seem accessible. Perhaps the easiest work-around is to modify the scala launch script to store the -classpath parameter string in an environment variable.

Assuming the desired Scala classpath can be determined, it can be passed to the embedded Scala interpreter via: settings.classpath.value = ...

Update: although the Scala classpath string may not be directly attainable from the Scala runtime, @Eugene points out that it can be extracted from the context classloader. Thanks.

Kipton Barros
  • 21,002
  • 4
  • 67
  • 80