50 votes

La création d'un fichier jar à partir d'un fichier Scala

Je suis nouveau à la Scala et ne sais pas Java. Je veux créer un fichier jar d'une simple Scala de fichier. Donc, j'ai mon HelloWorld.scala, de générer un HelloWorld.jar.

Le manifeste.mf:

Main-Class: HelloWorld

Dans la console j'ai exécuter:

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)

55voto

McDowell Points 62645

Exemple de structure de répertoire:

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!")
    }
  }
}

Le MANIFESTE.MF:

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

construire.chauve-souris:

@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


Pour utiliser avec succès le -jar interrupteur, vous avez besoin de deux entrées dans le META-INF/MANIFEST.MF fichier: la classe principale; les Url relatives à toutes les dépendances. Les notes de documentation:

-pot

Exécuter un programme encapsulé dans une Fichier JAR. Le premier argument est l' nom d'un fichier JAR au lieu d'un démarrage du nom de la classe. Pour que cette possibilité de travailler, le manifeste de l' JAR fichier doit contenir une ligne de la forme Principale de la Classe: nom de la classe. Ici, classname identifie la classe ayant le public static void main(String[] args) méthode qui sert de l'application du point de départ. Voir la Pot de référence de l'outil page et le Bocal piste de la Java Tutoriel pour informations sur le travail avec Jar les fichiers et les Jar-fichier manifeste.

Lorsque vous utilisez cette option, le fichier JAR est la source de toutes les classes de l'utilisateur, et d'autres du chemin de classe, les paramètres sont ignorés.

(Note: les fichiers JAR peuvent être inspectés avec la plupart des ZIP applications; je doute de la négligence utilisation des espaces dans les noms de répertoire dans le script de commandes; Scala code runner version 2.7.4.final .)


Pour l'exhaustivité, l'équivalent d'un script bash:

#!/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

10voto

Matt Reynolds Points 111

Parce que Scala scripts nécessitent la Scala bibliothèques à être installé, vous devrez inclure la Scala d'exécution le long de avec votre POT.

Il existe de nombreuses stratégies pour ce faire, comme jar jar, mais en fin de compte la question que vous voyez n'est que le processus Java vous avez commencé ne peut pas trouver la Scala Pots.

Pour un simple script autonome, je vous recommande d'utiliser jar jar, sinon, vous devriez commencer à regarder une dépendance de l'outil de gestion, ou d'obliger les utilisateurs à installer Scala dans le JDK.

4voto

tommy chheng Points 3156

Vous pouvez également utiliser maven et le maven-scala-plugin. Une fois que vous configurez maven, vous pouvez faire mvn package et il permettra de créer votre bocal pour vous.

2voto

xhalarin Points 21

J'ai modifié le script bash en ajoutant un peu d'intelligence, y compris l'auto-génération de manifestes.

Ce scénario suppose que l'objet principal est le même nom que le fichier qu'il est dans (sensible à la casse). Aussi, soit le nom du répertoire courant doit être égal au principal, le nom de l'objet ou de l'objet principal nom doit être fournie en tant que paramètre de ligne de commande. Lancer ce script dans le répertoire racine de votre projet. Modifier les variables en haut que nécessaire.

Attention, le script va générer le bin et dist dossiers et les EFFACE tout le contenu existant dans la corbeille.


#!/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 " "

2voto

user403090 Points 21

Une chose qui peut causer un problème similaire (bien que ce n'est pas le problème dans la question initiale ci-dessus) est que la machine virtuelle Java semble exiger que la principale méthode renvoie void. En Scala, on peut écrire quelque chose comme (observer l' =-signe dans la définition des principaux):

object MainProgram {

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

où les principaux retourne en fait un GUI-objet (c'est à dire qu'il n'est pas void), mais le programme fonctionne bien quand nous commençons à l'aide de la scala de commande.

Si nous avons le paquet de ce code dans un jar-file, avec MainProgram comme le Principal-Classe, la machine virtuelle Java va se plaindre qu'il n'y a pas la fonction principale, depuis le type de retour de notre main n'est pas void (je trouve cette plainte un peu étrange, étant donné que le type de retour n'est pas partie de la signature).

Nous n'avons pas de problèmes si nous avons laissé de côté l' =-signe dans l'en-tête de la principale, ou si nous les avons explicitement déclarée comme Unit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X