views:

260

answers:

1

Let's say I have this Hello.scala.

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello, world!")
  }
}

I could run 'scalac' to get HelloWorld.class and HelloWorld$.class. I can run using 'scala -classpath . Hello'. But I can't run 'java -cp . Hello'.

  • Why is this? Isn't scala interoperable with Java?
  • Is there any way to run scala's class with Java?
  • Why the scalac produces two class files?
  • Does scala have something like 'lein uber'? I mean, does scala have some tools that generates one jar file for distribution purposes?

proguard setup

Thanks to Moritz, I could make one jar file that be run with java. This is the overall structure.

|-- classes
|   |-- HelloWorld$.class
|   |-- HelloWorld.class
|   `-- META-INF
|       `-- MANIFEST.MF
|-- main.jar
`-- your.pro

your.pro has the following contents.

-injar classes
-injar /Users/smcho/bin/scala/lib/scala-library.jar(!META-INF/MANIFEST.MF)
-outjar main.jar
-libraryjar /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Classes/classes.jar

-dontwarn
-dontnote
-ignorewarnings

-optimizationpasses 2
-optimizations !code/allocation/variable

-keep,allowoptimization,allowshrinking class * { *; }
-keepattributes SourceFile,LineNumberTable

-keepclasseswithmembers public class HelloWorld { public static void main(java.lang.String[]); }

MAINFEST.MF has following setup. Don't forget to include [CR] or blank line.

Main-Class: HelloWorld

I download the proguard 4.5.1 to put it in ~/bin/proguard4.5.1. Running proguard, I could make the jar (main.jar), and it works fine.

prosseek:classes smcho$ java -Xmx512m -jar /Users/smcho/bin/proguard4.5.1/lib/proguard.jar @your.pro

ProGuard, version 4.5.1
Reading program directory [/Users/smcho/Desktop/scala/proguard/classes/classes]
Reading program jar [/Users/smcho/bin/scala/lib/scala-library.jar] (filtered)
Reading library jar [/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar]
Preparing output jar [/Users/smcho/Desktop/scala/proguard/classes/main.jar]
  Copying resources from program directory [/Users/smcho/Desktop/scala/proguard/classes/classes]
  Copying resources from program jar [/Users/smcho/bin/scala/lib/scala-library.jar] (filtered)
prosseek:classes smcho$ java -jar main.jar hello

I upload the example zip file here. And, scalar source code here.

+10  A: 

You need to add Scala to the classpath, e.g.

-classpath scala-library.jar:.

or by adding

-Xbootclasspath/a:scala-library.jar

to the VM arguments.

Addition:

Sorry, did not see that last question. If you want do distribute single JAR files many people use ProGuard to ship the classes needed from the scala-library.jar along with your classes in one jar.

Second Edit:

Assuming you have your .class-files and your META-INF folder containing the MANIFEST.MF in a folder called classes you can use the following Proguard configuration (after adjusting the paths, e.g. you need rt.jar on Linux/Windows instead of classes.jar on Mac OS) saved e.g. as your.pro:

-injar classes
-injar /opt/local/share/scala-2.8/lib/scala-library.jar(!META-INF/MANIFEST.MF)
-outjar main.jar
-libraryjar /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Classes/classes.jar

-dontwarn
-dontnote
-ignorewarnings

-optimizationpasses 2
-optimizations !code/allocation/variable

-keep,allowoptimization,allowshrinking class * { *; }
-keepattributes SourceFile,LineNumberTable

-keepclasseswithmembers public class your.Main { public static void main(java.lang.String[]); }

Now you can create main.jar with

java -Xmx512m -jar proguard.jar @your.pro

Eventually you have to set the -Xmx a bit higher. Some more info can be found on the SBT Wiki.

Moritz
@Moritz : Thanks for the answer, and I could run scala class with Java. But for making one jar file, could you give me some example how to do that? It seems that I have to make jar out of class first to make one big jar. Is this correct?
prosseek
@prosseek updated that. Although the name of the parameter is "-injar" Proguard actually also accepts a directory as input
Moritz
@Moritz : I tested by following your answer, but I couldn't get main.jar. Could you check that?
prosseek
@prosseek you have two errors in your setup: first you have to replace `your.Main` with `HelloWorld` in your.pro and second you have to copy the META-INF folder to classes if you want it to be included in the resulting jar.
Moritz
@Moritz : I could make the jar, but it doesn't seem to work. Could you check that once more? I uploaded the example files also.
prosseek
@prosseek: your `MANIFEST.MF` is not valid: every line has to be terminated by a newline and you are missing the line `Manifest-Version: 1.0` (though it should work without that line - but I would add it). Fixing that I could build and run the jar from the files you supplied.
Moritz
@Moritz : Thanks a lot, it works fine.
prosseek
Typo: `booclasspath`? Boo! ;-) Should be `bootclasspath`.
Jesper