Include Dependencies in JAR using SBT package - scala

Apparently project dependencies are not being packaged into the jar generated by:
sbt package
How can dependencies be included?

Well, I use sbt-assembly plugin to create jar with dependencies,
(1) add sbt-assembly to projects/assembly.sbt
echo 'addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.8")' > project/assembly.sbt
(2) run sbt clean assembly to build the jar.
It will create ${name}-assembly-${version}.jar in target/scala-${scalaVersion}
(3) Only in case you get infamous de-duplicate error, use assemblyMergeStrategy as described in here

There's a project called onejar that will package a project and all its dependencies into a single jar file. There is an SBT plugin as well:
https://github.com/sbt/sbt-onejar
However if you're just looking to create a standard package (deb, rpm, etc.) there is sbt-native-packager:
https://github.com/sbt/sbt-native-packager
It can place all your dependencies into a Linux package and add the appropriate wrappers to load all your dependencies and start your program or service.

Related

SBT Compile for uber jar

What is the best way to make a SBT project work in offline environment?
There is any ways to compile it outside (in network env),
e.g uber jar with all its dependencies, and then in the offline env
just run it?
For example in Java Maven,
We can compile it with uber jar with all dependencies,
and then in the offline env just java -jar MyJar.jar ...
Thanks.
Best bet for creating an uber/fat jar is the sbt assembly plugin. Include it in your project by putting something like the following in project/assembly.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
Then just running sbt assembly should create a jar with all the dependencies in target/scala_$SCALA_VERSION. You may need to designate a main class for the jar if you want to run it with java -jar (as opposed to java -cp $jarfile $mainclass):
mainClass in assembly := Some("package.mainClass")

Running Scala Script in sbt project

How can i run a scala script inside a sbt project which can access all classes of the sbt project and typesafe config as well? Basically I want the script to run in a similar way as the sbt console.
one option is to assemble a jar using sbt-assembly
you would need to add the following to a .sbt file to your project directory
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")
and add a minimum of two lines to your build file.
assemblyJarName in assembly := "something.jar"
mainClass in assembly := Some("com.example.Main")
then you can run the 'assembly' task from sbt, this will build and executable "fat" jar with all your dependencies and configuration.
You can use the launcher and the command system to implement an interactive appliation with autocomplete etc.
Here is a tutorial:
http://www.scala-sbt.org/0.13/docs/Command-Line-Applications.html
You have to invoke the application separately, though; I don't think it is possible to run it directly from the sbt prompt within the application directory.

How to use external dependencies in sbt's .scala files?

This is for Scala 2.11.1 and sbt 0.13.5.
Say I have a Scala/sbt project with the following directory structure:
root/
build.sbt
src/ ..
project/
plugins.sbt
build.properties
LolUtils.scala
and I want to use some external library in LolUtils.scala. How is this generally accomplished in sbt?
If I simply add the libs I need into build.sbt via libraryDependencies += .. then it doesn't find them and fails on the import line with not found: object ...
If I add a separate project/build.sbt, for some reason it starts failing to resolve my plugins, plus I need to manually specify the Scala version in the nested project/build.sbt, which is unnecessary duplication.
What's the best way to accomplish this?
sbt is recursive which means that it uses itself to compile a build definition, i.e. *.sbt files and *.scala files under project directory. To add extra dependencies to use them in the build definition you have to declare them in a project/build.sbt.
There is one caveat to that. You can set any scalaVersion to your project, that is in build.sbt, but you should not modify scalaVersion in the project/build.sbt as it might conflict with the version sbt itself uses (that may or may not lead to binary incompatibility for plugins).
Sbt 0.13.5 is using Scala 2.10.4, and the library you're going to use must be compatible with that particular version of Scala.
> about
[info] This is sbt 0.13.5
...
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.4

How to resolve a non-jar (dll/jnilib) library dependencies in sbt?

In a SBT build.sbt project file, is it possible to retrieve library dependencies which are not bundled as jar?
In my case, I am trying to use QTSampledSP which requires .dll and .jnilib libraries.
To download the artifact, you need to make Ivy (and hence sbt) explicitly aware of the DLL artifact. Add the following to build.sbt in your project.
lazy val QtSampledJniLibArt = Artifact("qtsampledsp-osx", "jnilib", "jnilib")
libraryDependencies += "com.tagtraum" % "qtsampledsp-osx" % "0.9.6" artifacts(QtSampledJniLibArt)
resolvers += "beatunes" at "http://www.beatunes.com/repo/maven2"
Then you need to tell sbt to pay attention to these artifacts (again build.sbt):
classpathTypes ++= Set("jnilib", "dll")
By default, sbt will only add a few types into the classpath (and jnilib and dll are not amongst them).
[sbt-0-13-1]> help classpathTypes
Artifact types that are included on the classpath.
[sbt-0-13-1]> show classpathTypes
[info] Set(eclipse-plugin, bundle, hk2-jar, orbit, jar)
Since these DLLs/jnilibs are needed on the classpath to run correctly, the above setting classpathTypes where you add the additional types will correct things as you can see below (don't forget to reload when in sbt console).
[sbt-0-13-1]> show classpathTypes
[info] Set(eclipse-plugin, bundle, hk2-jar, jnilib, orbit, jar, dll)
If you need to look in more detail at these files, check out the update report (from the update task) where you can inspect all configurations/modules/artifacts. Run show update in sbt console and look at the files in target/resolution-cache/reports.

Including Hyperic Sigar library within jar while using sbt assembly for Scala project

I'm building a Scala project with sbt and creating a fat jar with the sbt-assembly plugin. I'm able to add unmanaged jars (such as the Sigar jar) by adding the following to build.sbt.
unmanagedJars in Compile +=
file("lib/hyperic-sigar-1.6.4/sigar-bin/lib/sigar.jar")
However, when I try running this, I get the following error because the *.so libraries are not included in the jar.
no libsigar-amd64-linux.so in java.library.path
org.hyperic.sigar.SigarException: no libsigar-amd64-linux.so in java.library.path
at org.hyperic.sigar.Sigar.loadLibrary(Sigar.java:172)
at org.hyperic.sigar.Sigar.<clinit>(Sigar.java:100)
Exception in thread "main" java.lang.UnsatisfiedLinkError: org.hyperic.sigar.ptql.SigarProcessQuery.create(Ljava/lang/String;)V
at org.hyperic.sigar.ptql.SigarProcessQuery.create(Native Method)
at org.hyperic.sigar.ptql.ProcessQueryFactory.getQuery(ProcessQueryFactory.java:66)
at org.hyperic.sigar.ptql.ProcessFinder.findSingleProcess(ProcessFinder.java:44)
The libraries I want to include are in lib/hyperic-sigar-1.6.4/sigar-bin/lib/*.so and they need to be linked to a directory in the classpath within the jar. The only way I know of to do a mapping like this is:
resourceDirectory in Compile <<=
baseDirectory{ _ / "lib/hyperic-sigar-1.6.4/sigar-bin/lib" }
This causes the *.so libraries to be added to root of the jar, but not a specific directory. How can I specify a resource map to map from lib/hyperic-sigar-1.6.4/sigar-bin/lib/*.so to a directory in the classpath in my jar? What is the terminology for what I'm trying to do?
Assuming that sigar is indeed capable of loading native libs from classpath, this should do the trick:
libraryDependencies += "org.fusesource" % "sigar" % "1.6.4" classifier("native") classifier("")
Otherwise, you need to unpack them from the jar manually and provide proper java.library.path