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?
IntelliJ + scala plugin
I could get a jar that contains everything to run scala file file with IntelliJ + scala plugin, I think this is the better option than proguard.
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 `-- 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[]); }
MANIFEST.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
or
java -cp main.jar HelloWorld
I upload the example zip file here. And, scalar source code here.
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.
精彩评论