Add tools.jar in the classpath of sbt project
https://github.com/ensime/ensime-server/blob/master/build.sbt#L35
// epic hack to get the tools.jar JDK dependency
val JavaTools = List[Option[String]] (
// manual
sys.env.get("JDK_HOME"),
sys.env.get("JAVA_HOME"),
// osx
try Some("/usr/libexec/java_home".!!.trim)
catch {
case _: Throwable => None
},
// fallback
sys.props.get("java.home").map(new File(_).getParent),
sys.props.get("java.home")
).flatten.map { n =>
new File(n + "/lib/tools.jar")
}.find(_.exists).getOrElse (
throw new FileNotFoundException (
"""Could not automatically find the JDK/lib/tools.jar.
|You must explicitly set JDK_HOME or JAVA_HOME.""".stripMargin
)
)
Long answer, that might help you elsewhere.
If I want to know about something in SBT, I inspect
it:
> inspect console
[info] Task: Unit
[info] Description:
[info] Starts the Scala interpreter with the project classes on the classpath.
[info] Provided by:
[info] {file:/home/dcs/github/anti-xml/}default-39679a/compile:console
[info] Dependencies:
[info] compile:compilers(for console)
[info] compile:full-classpath
[info] compile:scalac-options(for console)
[info] compile:initial-commands(for console)
[info] compile:streams(for console)
[info] Delegates:
[info] compile:console
[info] *:console
[info] {.}/compile:console
[info] {.}/*:console
[info] */compile:console
[info] */*:console
[info] Related:
[info] test:console
Ok, there's an interesting dependency in compile:full-classpath
. I wish it were compile:full-classpath(for console)
, but it isn't. It shouldn't cause me trouble in this case, though. Let's inspect
it.
> inspect compile:full-classpath
[info] Task: scala.collection.Seq[sbt.Attributed[java.io.File]]
[info] Description:
[info] The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies.
[info] Provided by:
[info] {file:/home/dcs/github/anti-xml/}default-39679a/compile:full-classpath
[info] Dependencies:
[info] compile:exported-products
[info] compile:dependency-classpath
[info] Reverse dependencies:
[info] compile:console
[info] Delegates:
[info] compile:full-classpath
[info] *:full-classpath
[info] {.}/compile:full-classpath
[info] {.}/*:full-classpath
[info] */compile:full-classpath
[info] */*:full-classpath
[info] Related:
[info] compile:full-classpath(for doc)
[info] test:full-classpath
[info] test:full-classpath(for doc)
[info] *:full-classpath(for console)
[info] runtime:full-classpath
[info] compile:full-classpath(for console)
Ok, I could go further into the dependencies, but I don't think it's necessary. Let's see what's inside it:
> show compile:full-classpath
[warn] Credentials file /home/dcs/.ivy2/.credentials does not exist
[info] List(Attributed(/home/dcs/github/anti-xml/target/scala-2.9.1/classes), Attributed(/home/dcs/.sbt/boot/scala-2.9.1/lib/scala-library.jar))
[success] Total time: 0 s, completed Dec 7, 2011 3:49:30 PM
Ok, nothing unexpected there. Let's add tools.jar
.
To change something I have to use set
, and I have to respect a bunch of camel case and other rules to get it working. If I had compile:full-classpath(for console)
, that would become fullClasspath in Compile in console
. Note the uppercase in Compile
, and that full-classpath
became fullClasspath
, and the general reordering of element names. Details here.
I think one should be able to take the output of show
(or, at least, inspect
) and feed it right back to set
, but that's not the case (for now, anyway), so just learn these conversions rules.
I don't want to retype everything, just add one JAR file. I need to use +=
for that. The operators used to change thing can be found here.
The classpath seems to need some Attributed
stuff. Check the detailed docs on Classpath in the SBT wiki, and figure how to come up with one. Fortunately, most values I may want to change aren't as difficult to create as this one.
> set fullClasspath in Compile += Attributed.blank(file("/usr/lib/jvm/java-6-sun-1.6.0.26/lib/tools.jar"))
[info] Reapplying settings...
[info] Set current project to anti-xml (in build file:/home/dcs/github/anti-xml/)
Seems to have worked. Let's show
its content to confirm, since even writing compile
instead of Compile
might get it to change the wrong thing.
> show compile:full-classpath
[warn] Credentials file /home/dcs/.ivy2/.credentials does not exist
[info] List(Attributed(/home/dcs/github/anti-xml/target/scala-2.9.1/classes), Attributed(/home/dcs/.sbt/boot/scala-2.9.1/lib/scala-library.jar), Attributed(/usr/lib/jvm/java-6-sun-1.6.0.26/lib/tools.jar))
[success] Total time: 0 s, completed Dec 7, 2011 3:50:07 PM
Yep, there it is. Let's test it:
> console
[warn] Credentials file /home/dcs/.ivy2/.credentials does not exist
[info] Starting scala interpreter...
[info]
import com.codecommit.antixml._
bookstore: com.codecommit.antixml.Elem = <bookstore><book><title>For Whom the Bell Tolls</title><author>Hemmingway</author></book><book><title>I, Robot</title><author>Isaac Asimov</author></book><book><title>Programming Scala</title><author>Dean Wampler</author><author>Alex Payne</author></book></bookstore>
books: com.codecommit.antixml.Zipper[com.codecommit.antixml.Elem] = <book><title>For Whom the Bell Tolls</title><author>Hemmingway</author></book><book><title>I, Robot</title><author>Isaac Asimov</author></book><book><title>Programming Scala</title><author>Dean Wampler</author><author>Alex Payne</author></book>
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :javap com.codecommit.antixml.Elem
Compiled from "node.scala"
public class com.codecommit.antixml.Elem extends java.lang.Object implements com.codecommit.antixml.Node,com.codecommit.antixml.Selectable,scala.ScalaObject,scala.Product,scala.Serializable{
public static final scala.Function1 tupled();
public static final scala.Function1 curry();
public static final scala.Function1 curried();
public static final boolean isValidName(java.lang.String);
public scala.collection.Iterator productIterator();
public scala.collection.Iterator productElements();
public java.lang.Object $bslash(com.codecommit.antixml.Selector, com.codecommit.antixml.CanBuildFromWithZipper);
public java.lang.Object $bslash$bslash(com.codecommit.antixml.Selector, com.codecommit.antixml.CanBuildFromWithZipper);
public java.lang.Object $bslash$bslash$bang(com.codecommit.antixml.Selector, com.codecommit.antixml.CanBuildFromWithZipper);
public java.lang.Object select(com.codecommit.antixml.Selector, com.codecommit.antixml.CanBuildFromWithZipper);
public com.codecommit.antixml.Zipper toZipper();
public scala.Option prefix();
public java.lang.String name();
public com.codecommit.antixml.Attributes attrs();
public scala.collection.immutable.Map scope();
public com.codecommit.antixml.Group children();
public com.codecommit.antixml.Elem canonicalize();
public java.lang.String toString();
public com.codecommit.antixml.Group toGroup();
public com.codecommit.antixml.Group copy$default$5();
public scala.collection.immutable.Map copy$default$4();
public com.codecommit.antixml.Attributes copy$default$3();
public java.lang.String copy$default$2();
public scala.Option copy$default$1();
public com.codecommit.antixml.Elem copy(scala.Option, java.lang.String, com.codecommit.antixml.Attributes, scala.collection.immutable.Map, com.codecommit.antixml.Group);
public int hashCode();
public boolean equals(java.lang.Object);
public java.lang.String productPrefix();
public int productArity();
public java.lang.Object productElement(int);
public boolean canEqual(java.lang.Object);
public com.codecommit.antixml.Elem(scala.Option, java.lang.String, com.codecommit.antixml.Attributes, scala.collection.immutable.Map, com.codecommit.antixml.Group);
}
Success!!!
Of course, this session is a lie. It took much longer for me to arrive there, but that's mostly practice.