Frage

Ich bin neu in Scala und weiß nicht, Java. Ich möchte aus einer einfachen Scala-Datei eine JAR-Datei erstellen. Also ich habe meine HelloWorld.scala, eine HelloWorld.jar erzeugen.

Manifest.mf:

Main-Class: HelloWorld

In der Konsole Ich betreiben:

fsc HelloWorld.scala
jar -cvfm HelloWorld.jar Manifest.mf HelloWorld\$.class HelloWorld.class
java -jar HelloWorld.jar 
  => "Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld/jar"

java -cp HelloWorld.jar HelloWorld 
  => Exception in thread "main" java.lang.NoClassDefFoundError: scala/ScalaObject
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:280)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
    at hoppity.main(HelloWorld.scala)
War es hilfreich?

Lösung

Beispielverzeichnisstruktur:

X:\scala\bin
X:\scala\build.bat
X:\scala\MANIFEST.MF
X:\scala\src
X:\scala\src\foo
X:\scala\src\foo\HelloWorld.scala

HelloWorld.scala:

//file: foo/HelloWorld.scala
package foo {
  object HelloWorld {
    def main(args: Array[String]) {
      println("Hello, world!")
    }
  }
}

MANIFEST.MF:

Main-Class: foo.HelloWorld
Class-Path: scala-library.jar

build.bat:

@ECHO OFF

IF EXIST hellow.jar DEL hellow.jar
IF NOT EXIST scala-library.jar COPY %SCALA_HOME%\lib\scala-library.jar .

CALL scalac -sourcepath src -d bin src\foo\HelloWorld.scala

CD bin
jar -cfm ..\hellow.jar ..\MANIFEST.MF *.*
CD ..

java -jar hellow.jar

Um erfolgreich die verwenden -jar Schalter, müssen Sie zwei Einträge in der META-INF / MANIFEST.MF Datei: die Hauptklasse; relativer URLs auf irgendwelche Abhängigkeiten. Die Dokumentation Hinweise:

  

-jar

     

Führen Sie ein Programm in einem gekapselten   JAR-Datei. Das erste Argument ist die   Namen einer JAR-Datei anstelle eines   Startklassennamen. Damit diese   Option zu arbeiten, das Manifest der   JAR-Datei muss eine Zeile der enthalten   bilden Main-Klasse: Klassenname. Hier,   Klassennamen identifiziert die Klasse mit   die public static void main (String []   args) Methode, die als dient   Anwendung Ausgangspunkt. siehe   JAR-Tool Referenzseite und die Jar   Spur des Java Tutorial für   Informationen über die Arbeit mit Glas   Dateien und Jar-Datei Manifeste.

     

Wenn Sie diese Option verwenden, die JAR-Datei   ist die Quelle aller Benutzerklassen,    und andere Benutzerklassenpfad-Einstellungen ignoriert werden.

(Hinweise:. JAR-Dateien können mit den meisten ZIP-Anwendungen überprüft werden; ich wahrscheinlich Vernachlässigung Umgang mit Leerzeichen im Verzeichnisnamen im Batch-Skript, Scala Code runner Version 2.7.4.final)


Für die Vollständigkeit, ein äquivalenter Bash-Skript:

#!/bin/bash

if [ ! $SCALA_HOME ]
then
    echo ERROR: set a SCALA_HOME environment variable
    exit
fi

if [ ! -f scala-library.jar ]
then
    cp $SCALA_HOME/lib/scala-library.jar .
fi

scalac -sourcepath src -d bin src/foo/HelloWorld.scala

cd bin
jar -cfm ../hellow.jar ../MANIFEST.MF *
cd ..

java -jar hellow.jar

Andere Tipps

Da Scala Skripte die Scala Bibliotheken erfordern installiert werden, werden Sie die Scala Laufzeit zusammen mit Ihrem JAR enthalten müssen.

Es gibt viele Strategien, dies zu tun, wie zum Beispiel jar jar , aber letztlich die Frage Sie sehen, ist, dass die Java-Prozess Sie begonnen haben nicht die Scala JAR-Dateien finden.

Für einen einfachen Stand-alone-Skript, würde ich empfehlen, Jar Jar verwenden, andernfalls sollten Sie bei einem Abhängigkeits-Management-Tool suchen starten oder Benutzer benötigen Scala in dem JDK installieren .

Ich landete mit sbt Montage , es ist wirklich einfach zu bedienen. Ich habe eine Datei assembly.sbt in das project/ im Stammverzeichnis des Projektes mit einem Einzeiler (Beachten Sie Ihre Version werden müssen möglicherweise geändert) genannt.

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

Dann einfach die assembly Aufgabe in sbt ausführen:

> assembly

oder nur 'sbt Assembly' in dem Projektstammverzeichnis

$ sbt assembly

Es wird zuerst die Tests ausgeführt und dann wird es das neue Glas in das target/ Verzeichnis (vorausgesetzt, dass meine build.sbt bereits alle meine Abhängigkeiten Listen) erzeugen.

In meinem Fall habe ich nur, dass .jar Datei ausführbar machen, benennen Sie die Erweiterung zu entfernen, und es ist bereit zu versenden!

Auch wenn Sie ein Kommandozeilen-Tool tun, vergessen Sie nicht, ein hinzufügen Mann (ich hasse Skripte ohne richtigen manpages oder mit mehrseitigen Klartext-Dokumentation, die nicht einmal in einen Pager für Sie geleitet wird).

Sie können auch Maven verwenden und die Maven-scala-Plugin. Sobald Sie Maven einstellen, können Sie mvn Paket nur tun, und es wird für Sie Ihr Glas erstellen.

Ich habe versucht MyDowell Methode zu reproduzieren. Schließlich konnte ich es funktioniert. Allerdings finde ich, dass die Antwort allerdings ein wenig zu kompliziert für einen Anfänger korrigieren (insbesondere die Verzeichnisstruktur ist unnötig kompliziert).

kann ich dieses Ergebnis mit sehr simplen Mitteln reproduzieren. Zunächst einmal gibt es nur ein Verzeichnis ist, die enthält drei Dateien:

helloworld.scala
MANIFEST.MF
scala-library.jar

helloworld.scala

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

MANIFEST.MF:

Main-Class: HelloWorld
Class-Path: scala-library.jar

zuerst kompilieren helloworld.scala:

scalac helloworld.scala

erstellen Sie dann das Glas:

\progra~1\java\jdk18~1.0_4\bin\jar -cfm helloworld.jar MANIFEST.MF .

Jetzt können Sie führen Sie es mit:

java -jar helloworld.jar

Ich fand diese einfache Lösung, weil das Original nicht funktionierte. Später fand ich heraus, dass nicht, weil es falsch ist, aber wegen eines trivialen Fehler: Wenn ich nicht die zweite Zeile in MANIFEST.MF mit einem Newline schließen tun, dann wird diese Zeile ignoriert. Dies dauerte eine Stunde, um herauszufinden, und ich versuchte, alle anderen Dinge vor, in dem Prozess diese sehr einfache Lösung zu finden.

Ich will nicht schreiben, warum und wie ist ziemlich einfach, die Lösung zeigen, was in meinem Fall war (über Linux Ubuntu Kommandozeile):

1)

mkdir scala-jar-example
cd scala-jar-example

2)

nano Hello.scala
object Hello extends App   {  println("Hello, world")   }

3)

nano build.sbt
import AssemblyKeys._

assemblySettings

name := "MyProject"

version := "1.0"

scalaVersion := "2.11.0"

3)

mkdir project
cd project 
nano plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.9.1")

4)

cd ../   
sbt assembly

5)

java -jar target/target/scala-2.11/MyProject-assembly-1.0.jar
>> Hello, world

ich das Bash-Skript geändert einig Intelligence einschließlich Auto-Manifest Generation hinzufügen.

Dieses Skript geht davon aus, dass das Hauptziel die gleiche wie die Datei mit dem Namen wird es in dem (Groß- und Kleinschreibung). Auch entweder der aktuelle Verzeichnis-Name muss gleich mit dem Hauptobjektnamen oder das Hauptobjekt Name sollte als Befehlszeilenparameter zur Verfügung gestellt werden. Starten Sie dieses Skript aus dem Stammverzeichnis Ihres Projekts. Ändern Sie die Variablen an der Spitze, wie erforderlich.

Beachten Sie, dass das Skript die sind und dist Ordner erzeugen wird und alle vorhandenen Inhalte in Bin löschen.


#!/bin/bash

SC_DIST_PATH=dist
SC_SRC_PATH=src
SC_BIN_PATH=bin
SC_INCLUDE_LIB_JAR=scala-library.jar
SC_MANIFEST_PATH=MANIFEST.MF
SC_STARTING_PATH=$(pwd)

if [[ ! $SCALA_HOME ]] ; then
    echo "ERROR: set a SCALA_HOME environment variable"
    exit 1
fi

if [[ ! -f $SCALA_HOME/lib/$SC_INCLUDE_LIB_JAR ]] ; then
    echo "ERROR: Cannot find Scala Libraries!"
    exit 1
fi

if [[ -z "$1" ]] ; then
    SC_APP=$(basename $SC_STARTING_PATH)
else
    SC_APP=$1
fi

[[ ! -d $SC_DIST_PATH ]] && mkdir $SC_DIST_PATH

if [[ ! -d $SC_BIN_PATH ]] ; then
    mkdir "$SC_BIN_PATH"
else
    rm -r "$SC_BIN_PATH"
    if [[ -d $SC_BIN_PATH ]] ; then
        echo "ERROR:  Cannot remove temp compile directory:  $SC_BIN_PATH"
        exit 1
    fi
    mkdir "$SC_BIN_PATH"
fi

if [[ ! -d $SC_SRC_PATH ]] || [[ ! -d $SC_DIST_PATH ]] || [[ ! -d $SC_BIN_PATH ]] ; then
    echo "ERROR: Directory not found!:  $SC_SRC_PATH or $SC_DIST_PATH or $SC_BIN_PATH"
    exit 1
fi

if [[ ! -f $SC_DIST_PATH/$SC_INCLUDE_LIB_JAR ]] ; then
    cp "$SCALA_HOME/lib/$SC_INCLUDE_LIB_JAR" "$SC_DIST_PATH"
fi

SCALA_MAIN=$(find ./$SC_SRC_PATH -name "$SC_APP.scala")
COMPILE_STATUS=$?
SCALA_MAIN_COUNT=$(echo "$SCALA_MAIN" | wc -l)

if [[ $SCALA_MAIN_COUNT != "1" ]] || [[ ! $COMPILE_STATUS == 0 ]] ; then
    echo "Main source file not found or too many exist!:  $SC_APP.scala"
    exit 1
fi

if [[ -f $SC_DIST_PATH/$SC_APP.jar ]] ; then
    rm "$SC_DIST_PATH/$SC_APP.jar"  
    if [[ -f $SC_DIST_PATH/$SC_APP.jar ]] ; then
        echo "Unable to remove existing distribution!:  $SC_DIST_PATH/$SC_APP.jar"
        exit 1
    fi
fi

if [[ ! -f $SC_MANIFEST_PATH ]] ; then
    LEN_BASE=$(echo $(( $(echo "./$SC_SRC_PATH" |wc -c) - 0 )))
    SC_MAIN_CLASS=$(echo $SCALA_MAIN |cut --complement -c1-$LEN_BASE)
    SC_MAIN_CLASS=${SC_MAIN_CLASS%%.*}
    SC_MAIN_CLASS=$(echo $SC_MAIN_CLASS |awk '{gsub( "/", "'"."'"); print}')

    echo $(echo "Main-Class: "$SC_MAIN_CLASS) > $SC_MANIFEST_PATH
    echo $(echo "Class-Path: "$SC_INCLUDE_LIB_JAR) >> $SC_MANIFEST_PATH
fi

scalac -sourcepath $SC_SRC_PATH -d $SC_BIN_PATH $SCALA_MAIN
COMPILE_STATUS=$?

if [[ $COMPILE_STATUS != "0" ]] ; then
    echo "Compile Failed!"
    exit 1
fi

cd "$SC_BIN_PATH"
jar -cfm ../$SC_DIST_PATH/$SC_APP.jar ../$SC_MANIFEST_PATH *
COMPILE_STATUS=$?
cd "$SC_STARTING_PATH"

if  [[ $COMPILE_STATUS != "0" ]] || [[ ! -f $SC_DIST_PATH/$SC_APP.jar ]] ; then
    echo "JAR Build Failed!"
    exit 1
fi

echo " "
echo "BUILD COMPLETE!... TO LAUNCH:  java -jar $SC_DIST_PATH/$SC_APP.jar"
echo " "

Eine Sache, die ein ähnliches Problem verursachen kann (obwohl es oben nicht das Problem in der Ausgangsfrage ist) ist, dass der Java-VM zu fordern scheint, dass die Haupt-Methode gibt void.

: In Scala können wir so etwas wie ( beachten = -Zeichen in der Definition des Haupt ) schreiben
object MainProgram {

  def main(args: Array[String]) = {
    new GUI(args)
  }
}

, wo Haupt tatsächlich ein GUI-Objekt zurückgibt (das heißt, es ist nicht void), aber das Programm wird gut laufen, wenn wir es mit dem scala-Befehl starten.

Wenn wir diesen Code in eine Jar-Datei verpacken, mit MainProgram als Main-Klasse, wird die Java vm beklagen, dass es keine Hauptfunktion, da der Rückgabetyp unserer wichtigsten ist void nicht (ich finde diese Beschwerde etwas seltsam da der Rückgabetyp nicht Teil der Signatur ist).

Wir würden keine Probleme haben, wenn wir das = -Zeichen in der Kopfzeile des Hauptes ausgelassen, oder wenn wir ausdrücklich als Unit erklärt.

Wenn Sie nicht wünschen, SBT Einrichtungen nutzen ich die Verwendung einer Make-Datei empfehlen.

Hier ist ein Beispiel, in dem foo Paket wird ersetzt durch foo.bar.myApp auf Vollständigkeit.

Make-Datei

NAME=HelloWorld
JARNAME=helloworld

PACKAGE=foo.bar.myApp
PATHPACK=$(subst .,/,$(PACKAGE))

.DUMMY: default
default: $(NAME)

.DUMMY: help
help:
    @echo "make [$(NAME)]"
    @echo "make [jar|runJar]"
    @echo "make [clean|distClean|cleanAllJars|cleanScalaJar|cleanAppJar]"

.PRECIOUS: bin/$(PATHPACK)/%.class

bin/$(PATHPACK)/%.class: src/$(PATHPACK)/%.scala
    scalac -sourcepath src -d bin $<

scala-library.jar:
    cp $(SCALA_HOME)/lib/scala-library.jar .

.DUMMY: runjar
runJar: jar
    java -jar $(JARNAME).jar

.DUMMY: jar
jar: $(JARNAME).jar

MANIFEST.MF:
    @echo "Main-Class: $(PACKAGE).$(NAME)" > $@
    @echo "Class-Path: scala-library.jar" >> $@

$(JARNAME).jar: scala-library.jar bin/$(PATHPACK)/$(NAME).class \
                                MANIFEST.MF
    (cd bin && jar -cfm ../$(JARNAME).jar ../MANIFEST.MF *)

%: bin/$(PATHPACK)/%.class
    scala -cp bin $(PACKAGE).$@

.DUMMY: clean
clean:
    rm -R -f bin/* MANIFEST.MF

cleanAppJar:
    rm -f $(JARNAME).jar

cleanScalaJar:
    rm -f scala-library.jar

cleanAllJars: cleanAppJar cleanScalaJar

distClean cleanDist: clean cleanAllJars
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top