How to detect JavaFX runtime jar in sbt

2019-05-11 22:28发布

What I'd like to do is define javaHome in the beginning, either from an environment variable or from a fixed string as a default. Then, later, I would use that string.

This is what I've tried:

javaHome := Some(file("/Library/Java/JavaVirtualMachines/jdk1.7.0_10.jdk/Contents/Home"))

and later

unmanagedJars in Compile <+= (javaHome) { fn => Attributed.blank( fn + "/jre/lib/jfxrt.jar") }

I have tried to read the [reference][1] but it's really more complex than Scala itself. Please help.

I can bypass this by having a fixed string in the midst of the build file, but generally I don't like such.

Platform is OS X, sbt 0.12.1, JDK 7u10, Scala 2.9.2

Edit: Since I found a solution, I have removed error messages and two further (unsuccessful) tries since they would only confuse.

2条回答
太酷不给撩
2楼-- · 2019-05-11 22:53

<+= really is for appending to a "collection" setting, I don't think it is supported for string concatenation. Plus in your second attempt you are both trying to concatenate via an assignment operator (<+=) and concatenating by hand using the + operator, which is certainly not what you intended. just Replace <+= with <<= and it should make sbt happy.

unmanagedJars in Compile <<= javaHome map { jh => jh + "/jre/lib/jfxrt.jar" }

UPDATE: Turns out I misread your post and was completly wrong. You were right to use <+= to append to unamanagedJar, and the use of + was there just to create an absolute file path. Sorry a bout that. This time I acutally tried to fix it with sbt at hand, and managed to make it compile. I didn't actually test it against a real project though, I'll let you try it and report if it works as expected.

unmanagedJars in Compile <+= javaHome map { jh => Attributed.blank( new File( jh.getOrElse(sys.error("Error, could not get java home")),"jre/lib/jfxrt.jar" ) ) }

This is clearly not very nice though, there might be some helper somewhere to make it more readable.

查看更多
【Aperson】
3楼-- · 2019-05-11 23:15

Got this finally done. It seems the problem was partly in understanding the sbt value model (and its pure overuse of custom operators!), partly in getting to terms with the types used in sbt.

I will edit the question accordingly, but here are my findings (and solution).

  1. sbt values are pre-meditated. They are not variables in the way that I cannot set myOwn. The javaHome is a known value (or actually, a task?) of sbt.

  2. Having said that, I wonder why sbt cannot do a good job in finding a suitable JDK for me. Oh, well.

Tip: Use of val xxx: Nothing = expression is a great tool in finding the types of various things. One cannot have an instance of type Nothing so that always fails, with a nice error message informing the (unknown) type of the expression.

Here comes my javaHome detection code (from build.sbt):

//---
// Note: Wouldn't 'sbt' be able to provide us a nice default for this (the following logic
//      would deserve to be automatic, not in a project build script). AK 4-Jan-2013
//
javaHome := {
  var s = System.getenv("JAVA_HOME")
  if (s==null) {
    // tbd. try to detect JDK location on multiple platforms
    //
    // OS X: "/Library/Java/JavaVirtualMachines/jdk1.xxx.jdk/Contents/Home" with greatest id (i.e. "7.0_10")
    //
    s= "/Library/Java/JavaVirtualMachines/jdk1.7.0_10.jdk/Contents/Home"
  }
  //
  val dir = new File(s)
  if (!dir.exists) {
    throw new RuntimeException( "No JDK found - try setting 'JAVA_HOME'." )
  }
  //
  Some(dir)  // 'sbt' 'javaHome' value is ': Option[java.io.File]'
}

And here is the snippet (later in the same file) that uses it, making sure we have access to jfxrt.jar (the JavaFX 2.x runtime). Oracle (or sbt) should make this be on the classpath anyways, so all of this could be spared.

//---
// JavaFX
//
// Note: We shouldn't even need to say this at all. Part of Java 7 RT (since 7u06) and should come from there (right)
//      The downside is that now this also gets into the 'one-jar' .jar package (where it would not need to be,
//      and takes 15MB of space - of the 17MB package!) AKa 1-Nov-2012
//
unmanagedJars in Compile <+= javaHome map { jh /*: Option[File]*/ =>
  val dir: File = jh.getOrElse(null)    // unSome
  //
  val jfxJar = new File(dir, "/jre/lib/jfxrt.jar")
  if (!jfxJar.exists) {
    throw new RuntimeException( "JavaFX not detected (needs Java runtime 7u06 or later): "+ jfxJar.getPath )  // '.getPath' = full filename
  }
  Attributed.blank(jfxJar)
} 

Note that sbt does not allow empty lines within an entry. To avoid this I've used indented // lines where I wanted some white space.

查看更多
登录 后发表回答