50

私は Scala を初めて使用し、Java を知りません。単純な Scala ファイルから jar ファイルを作成したいと考えています。だから私は HelloWorld.scala を持っているので、HelloWorld.jar を生成します。

マニフェスト.mf:

Main-Class: HelloWorld

私が実行するコンソールで:

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)
4

9 に答える 9

55

サンプルディレクトリ構造:

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

-jarスイッチを正常に使用するには、 META-INF/MANIFEST.MFファイルに2つのエントリが必要です。依存関係への相対URL。ドキュメントノート:

-jar

JARファイルにカプセル化されたプログラムを実行します。最初の引数は、スタートアップクラス名ではなく、JARファイルの名前です。このオプションを機能させるには、JARファイルのマニフェストにMain-Class:classnameという形式の行が含まれている必要があります。ここで、classnameは、アプリケーションの開始点として機能するpublic static void main(String [] args)メソッドを持つクラスを識別します。JarファイルおよびJarファイルマニフェストの操作については、JarツールのリファレンスページおよびJavaチュートリアルのJarトレイルを参照してください。

このオプションを使用すると、JARファイルがすべてのユーザークラスのソースに なり、他のユーザークラスパス設定は無視されます。

(注:JARファイルはほとんどのZIPアプリケーションで検査できます。バッチスクリプトのディレクトリ名のスペースの処理はおそらく無視します。Scalaコードランナーバージョン2.7.4.final。)


完全を期すために、同等の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
于 2009-04-30T22:31:11.450 に答える
10

Scala スクリプトには Scala ライブラリをインストールする必要があるため、JAR とともに Scala ランタイムを含める必要があります。

jar jarなど、これを行うための多くの戦略がありますが、最終的に表示される問題は、開始した Java プロセスが Scala JAR を見つけられないことです。

単純なスタンドアロン スクリプトの場合は、jar jar を使用することをお勧めします。それ以外の場合は、依存関係管理ツールを検討するか、ユーザーにJDK にScala をインストールするように要求する必要があります。

于 2009-04-30T22:20:48.137 に答える
5

最終的にsbt assemblyを使用しましたが、使い方は本当に簡単です。assembly.sbtプロジェクトのルートにあるディレクトリに呼び出されるファイルproject/をワンライナーで追加しました (バージョンの変更が必要になる場合があることに注意してください)。

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

次に、次のassemblyタスクを実行しsbtます。

> assembly

または、プロジェクトのルート ディレクトリにある「sbt アセンブリ」

$ sbt assembly

target/最初にテストを実行し、次にディレクトリに新しい jar を生成します(mybuild.sbtがすべての依存関係を既にリストしているとします)。

私の場合、その.jarファイルを実行可能にし、名前を変更して拡張子を削除するだけで、出荷の準備が整います!

また、コマンド ライン ツールを使用している場合は、man ページを追加することを忘れないでください (適切なman ページのないスクリプトや、ページャーにパイプされていない複数ページのプレーン テキスト ドキュメントを含むスクリプトは嫌いです)。

于 2014-12-29T13:49:36.903 に答える
4

MyDowellの方法を再現してみました。最後に、私はそれを機能させることができました。ただし、答えは初心者には少し複雑すぎると思います(特に、ディレクトリ構造は不必要に複雑です)。

この結果は非常に単純な手段で再現できます。まず、3 つのファイルを含むディレクトリが 1 つだけあります。

helloworld.scala
MANIFEST.MF
scala-library.jar

helloworld.scala

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

マニフェスト.MF:

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

最初に helloworld.scala をコンパイルします。

scalac helloworld.scala

次に、jar を作成します。

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

これで、次のように実行できます。

java -jar helloworld.jar

元の解決策が機能しなかったため、この簡単な解決策を見つけました。後で、それが間違っているからではなく、些細なエラーが原因であることがわかりました。MANIFEST.MF の 2 行目を改行で閉じないと、この行は無視されます。これを見つけるのに1時間かかりましたが、この非常に単純な解決策を見つける過程で、以前に他のすべてのことを試しました.

于 2015-11-25T16:02:47.770 に答える
4

maven と maven-scala-plugin を使用することもできます。Maven をセットアップしたら、mvn package を実行するだけで、jar が作成されます。

于 2010-03-09T21:19:40.027 に答える
3

理由と方法を書きたくありませんが、私の場合に機能したソリューションを示すだけです(Linux Ubuntuコマンドライン経由):

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
于 2016-04-22T08:48:46.123 に答える
2

同様の問題を引き起こす可能性があることの 1 つは (上記の最初の質問の問題ではありませんが)、Java vm が main メソッドが を返すことを要求しているように見えることvoidです。Scala では、次のように書くことができます ( main の定義にある = 記号に注目してください):

object MainProgram {

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

ここで main は実際にはGUI-object を返します (つまり ではありませんvoid) が、プログラムは scala コマンドを使用して開始するとうまく実行されます。

このコードをメイン クラスとして jar ファイルにパッケージ化するとMainProgram、Java vm はメイン関数がないと文句を言うでしょうvoid。は署名の一部ではありません)。

main のヘッダーで = 記号を省略したり、明示的に として宣言したりしても、問題はありませんUnit

于 2010-07-27T08:52:27.643 に答える
2

自動マニフェスト生成を含むいくつかのインテリジェンスを追加して、bash スクリプトを変更しました。

このスクリプトは、メイン オブジェクトがファイルと同じ名前であることを前提としています (大文字と小文字が区別されます)。また、現在のディレクトリ名がメイン オブジェクト名と同じであるか、メイン オブジェクト名がコマンド ライン パラメータとして指定されている必要があります。プロジェクトのルート ディレクトリからこのスクリプトを起動します。必要に応じて上部の変数を変更します。

スクリプトは bin および dist フォルダーを生成し、bin 内の既存のコンテンツを消去することに注意してください。


#!/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 " "
于 2010-03-25T17:34:23.820 に答える