Scala and sbt

Posted on Monday, February 3, 2014


This guide goes over installing and using the sbt plugin.
This guide was written using an Ubuntu 12.04 server.



Installing scala


You could install scala with a simple apt-get (but I would suggest not doing so)


> sudo apt-get update
> sudo apt-get install scala


Doing this on a default deploy of Ubuntu 12.04 will give you Scala version 2.9.1 and OpenJDK 1.6.0_27




This is not what I want, I prefer using Oracles JVM


To install the Oracle Java JVM and the latest Scala run the following commands.

First install the Oracle JVM


>  sudo apt-get purge openjdk*
>  sudo apt-get install python-software-properties
>  sudo add-apt-repository ppa:webupd8team/java
>  sudo apt-get update
>  sudo apt-get install oracle-java7-installer
>  java -version


This installed Version 1.7.0_51-b13 (on 2/2/2014)









Run the following command to download the .tgz file from scala and untar it  (link obtained from http://scala-lang.org/download/2.10.3.html  [1])


  > wget http://scala-lang.org/files/archive/scala-2.10.3.tgz
  > tar xf scala-2.10.3.tgz


Now place the scala program in /usr/bin/scala
And make a ln to it



    > sudo mkdir /usr/lib/scala
    > sudo mv scala-2.10.3 /usr/lib/scala/
    > sudo touch /usr/bin/scala
    > sudo ln -fs /usr/lib/scala/scala-2.10.3/bin/scala /usr/bin/scala
    >  sudo chmod a+x /usr/bin/scala




Then edit my .bashrc file  (I had set JAVA_HOME here before)


  > cd
  > vi .bashrc


Updated JAVA_HOME to




 export JAVA_HOME=/usr/lib/jvm/java-7-oracle




Reload the bash file


  > source .bashrc



Open a new terminal and run scala


  > scala




Doing this deploy of Ubuntu 12.04 will give you Scala version 2.10.3 and OpenJDK 1.7.0_51



Install sbt-launch.jar


Information for this part was taken from the sbt install guide at http://www.scala-sbt.org/release/docs/Getting-Started/Setup.html [2]

Run the following to download and install sbt-launch.jar


> wget http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/0.13.1/sbt-launch.jar
> sudo mv sbt-launch.jar /bin


Create a run script for it at /bin/sbt


> sudo vi /bin/sbt


And place in it


SBT_OPTS="-Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M"
java $SBT_OPTS -jar `dirname $0`/sbt-launch.jar "$@"


Make it executable


> sudo chmod a+x /bin/sbt



Run it as a test


> sbt


Looks like it downloads a lot of libraries the first time




Real example


Set up the folder structure



From this page

sbt uses the same directory structure as Maven for source files by default.



Here is the structure

src/
  main/
    resources/
       <files to include in main jar here>
    scala/
       <main Scala sources>
    java/
       <main Java sources>
  test/
    resources
       <files to include in test jar here>
    scala/
       <test Scala sources>
    java/
       <test Java sources>


I am only concerned about scala code so my directory structure will be.

src/
  main/
    resources/
    scala/




I am going to make a test directory and within that directory create the above directory structure.  Here is the linux command line code to make that happen.


> cd
> mkdir test
> cd test
> mkdir -p src/main/resources
> mkdir src/main/scala



I am going to put my code in the package com.whiteboardcoder.hello so I need to make some more directories.


> mkdir -p src/main/scala/com/whiteboardcoder/hello



Create the code.


> vi src/main/scala/com/whiteboardcoder/hello/hw.scala



Here is the code


package com.whiteboardcoder.hello

object hw {
  def main(args: Array[String]){
    println("Hello World!")
  }
}



Create the build.sbt file


> vi build.sbt



Here is the basic build.sbt code


name:= "My Hello World Program"

version := "1.0"

scalaVersion := "2.10.3"



Now, as a test, compile it


> sbt compile




This will create a project and a target folder.  It will place the compiled code at

target/scala-2.10/classes/com/whiteboardcoder/hello/hw.class



According to http://www.scala-sbt.org/release/docs/Getting-Started/Running.html [3] sbt has the following commands

clean                - Deletes all generated files in the target directory
compile            - Compiles the main sources
test                  - Compiles and runs all tests
console            - Starts the Scala Interpreter
run                   - Runs the main class for the project
package           - Creates a jar file containing al the files in
                        src/main/resources and the classes compiled from
                        src/main/scala and src/main/java
help                 - Displays detailed help
reload              - Reloads the build definition


Now, as a test, run… clean compile package


> sbt clean compile package


This created a jar file named my-hello-world-program_2.10-1.0.jar at
target/scala-2.10/my-hello-world-program_2.10-1.0.jar

This name came from the build.sbt file the "name" setting

This makes me think…. I would like to set the main class for the jar package (Set in the Manifest)


Create jar with mainClass


Edit the build.sbt file


> vi build.sbt



Add the mainClass setting


name:= "My Hello World Program"

version := "1.0"

scalaVersion := "2.10.3"

mainClass in Compile := Some("com.whiteboardcoder.hello.hw")



As a quick test run it


> sbt clean compile run


The run used the mainClass





Now do a package (create a jar)


> sbt clean compile package



Try to run the compile jar


> java -jar target/scala-2.10/my-hello-world-program_2.10-1.0.jar


I get the following error

Exception in thread "main" java.lang.NoClassDefFoundError: scala/Predef$

I am missing scala-library.jar….

After looking around a bit it seems that sbt out of the box does not have a good way to combine all the necessary dependent jar files into one jar file.  But there are several other tools out there to help with this.

I found sbt-assembly at https://github.com/sbt/sbt-assembly [4]

This tool can be loaded automatically in your sbt build.  sbt uses Apache Ivy http://ant.apache.org/ivy/ [5].  I am not yet familiar with all that Ivy can do, but in this case it can download and install an sbt plugin in with one line of script.


Create a new file at project/plugins.sbt


> vi project/plugins.sbt


And add the following line to it.


addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.2")


Nothing more is needed as the default Ivy Repository has sbt-assembly in it http://www.scala-sbt.org/release/docs/Community/Community-Plugins.html  [6], otherwise I think you would have to append to the resolvers to tell sbt where to find the plugin.




Edit build.sbt


> vi build.sbt


With the following highlighted changes


import AssemblyKeys._

assemblySettings

name:= "My Hello World Program"

version := "1.0"

scalaVersion := "2.10.3"

jarName in assembly := "hello.jar"

mainClass in (Compile, assembly) := Some("com.whiteboardcoder.hello.hw")


This will import and set the assembly setting keys.  Then set the name of the jar to hello.jar

Now run, the first time you run this it will download the sbt-assembly plug-in


> sbt clean compile assembly



Try to run the compiled jar


> java -jar target/scala-2.10/hello.jar




That worked.

If you look in the jar file


> jar tf target/scala-2.10/hello.jar


You will see that it has all the scala libraries needed to run this program have been included



This makes the jar file about 13 MiB in size

That is it for this guide.  I hope someone finds this helpful.


References
[1]        Scala Download page
                Accessed 02/2014
[2]        sbt directory structure
                Accessed 02/2014
[3]        sbt Running
                Accessed 02/2014
[4]        github sbt-assembly
            https://github.com/sbt/sbt-assembly
                Accessed 02/2014
[5]        Apache Ivy
            http://ant.apache.org/ivy/
                Accessed 02/2014
[6]        Community Plugin

                Accessed 02/2014 

No comments:

Post a Comment