web-dev-qa-db-ja.com

sbt-packとsbt-assemblyの主な違いは何ですか?

sbt-pack プラグインを偶然見つけました。開発ストリームは 定常的 のようです。 (sbt-packのヘッドラインを引用する) "ディストリビューションを作成するための唯一のプラグインScala packages。"sbt-Assembly (他の機能の中でも)です。

プラグイン間の主な違いは何ですか?いつどちらを使用すればよいですか?

36
Jacek Laskowski

(免責事項:私はsbt-Assemblyを維持しています)

sbt-Assembly

sbt-Assembly はファットJARを作成します-コードとライブラリからのすべてのクラスファイルを含む単一のJARファイル。進化により、複数のJARが同じファイルパス(configまたはREADME fileなど)を提供する場合の競合を解決する方法も含まれます。すべてのライブラリJARの解凍が含まれるため、少し時間がかかりますが、これらは大量にキャッシュされます。

sbt-pack

sbt-pack は、すべてのライブラリJARをそのまま保持し、それらをtarget/packディレクトリに移動し(通常はそこにあるivyキャッシュとは対照的)、シェルスクリプトを作成して実行します。

sbt-native-packager

sbt-native-packager はsbt-packに似ていますが、sbtコミッターによって開始されました Josh Suereth 、現在は高度な能力によって維持されています Nepomuk Seiler =(muuki88とも呼ばれます)。プラグインは、Windows msiファイルやDebian debファイルのような多くのフォーマットをサポートしています。最近の追加は、 Dockerイメージ のサポートです。

これらはすべて、展開イメージを作成するための実行可能な手段です。アプリケーションをWebフレームワークにデプロイする場合など、特定のケースでは、1ダースではなく1つのファイルを処理する方が簡単な場合があります。

名誉ある言及: sbt-progard および sbt-onejar

69
Eugene Yokota

Eugene Yokotaの説明はこれで完了ですが、上記のプラグインとパッケージコマンドを使用方法と異なる結果が生成される方法について説明します。

ディレクトリ設定とbuild.sbt

lazy val commonSettings = Seq(
  organization := "stackOverFlow",
  scalaVersion := "2.11.12",
  version := "1.0",
)

lazy val app  = (project in file ("app")).
  enablePlugins(PackPlugin).
  settings(commonSettings)

上記build.sbt fileはappというプロジェクトを宣言し、appディレクトリにすべてのソースファイルを含めます。パックプラグインを有効にするには、enablePlugins(PackPlugin)をsbtファイルに含める必要があります。

また、以下の行をproject/plugins.sbtファイルに入れて、プロジェクトでパックプラグインを使用します

addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.9.3")
addSbtPlugin("com.eed3si9n" % "sbt-Assembly" % "0.14.5")

パッケージはデフォルトですでにsbtに統合されているため、addSbtPluginsを使用してプラグインを明示的に指定する必要はありません。ただし、sbt-packおよびsbt-Assemblyプラグインはデフォルトではsbtに含まれていないため、使用することを指定する必要があります。 addSbtPluginは、sbtに「プロジェクトでxxx、yyyプラグインを使用したい」と言う方法です。

また、。/ app/src/main/scalaに2つの不自然なscalaファイルを実装しました。

AppBar.scala

class AppBar {
  def printDescription() = println(AppBar.getDescription)
}

object AppBar {
  private val getDescription: String = "Hello World, I am AppBar"

  def main (args: Array[String]): Unit = {
    val appBar = new AppBar
    appBar.printDescription()
  }
}

AppFoo.scala

class AppFoo {
  def printDescription() = println(AppFoo.getDescription)
}

object AppFoo {
  private val getDescription: String = "Hello World, I am AppFoo"

  def main (args: Array[String]): Unit = {
    val appFoo = new AppFoo
    appFoo.printDescription()
  }
}

sbtパッケージ

これは、sbtに含まれている非常に基本的なsbtコマンドであり、jarファイルを通じてプロジェクトを配布するのに役立ちます。 packageコマンドによって生成されたjarファイルは、projectDirectoy/target/scala-2.11/app_2.11-1.0.jarにあります(ここでは、build.sbtファイルに含まれている指定されたscalaVersionおよびバージョン設定キーを使用して、jarを生成しますファイル名)。

Jarの中を見ると、sbtツールによって生成されたクラスファイルを確認できます。これは、app/src/main/scalaでソースをコンパイルした結果です。また、MANIFESTファイルも含まれています。

$vi  projectDirectoy/target/scala-2.11/app_2.11-1.0.jar

META-INF/MANIFEST.MF
AppBar$.class
AppBar.class
AppFoo.class
AppFoo$.class

App/src/main/scalaディレクトリにあるscalaファイルから生成されたクラスファイルのみが含まれることに注意してください。パッケージコマンドによって生成されたjarファイルには、scalaライブラリ内のコレクション(collection.mutable.Map.classなど)などのscala関連ライブラリが含まれていません。したがって、生成jarファイルには、実装したscalaソースから生成された最小限のクラスしか含まれていないため、プログラムを実行するにはscalaライブラリが必要になる場合があります。これが、jarファイルにAppBar.class、コンパニオンオブジェクトのAppBar $ .classなどが含まれている理由です。

sbt-Assembly

Eugene Yokotaが述べたように、sbt-Assemblyはjarファイルの生成を通じてプロジェクトを配布するのにも役立ちます。ただし、生成されたjarファイルには、ソースコードによって生成されたクラスファイルだけでなく、プログラムの実行に必要なすべてのライブラリも含まれます。たとえば、AppFooオブジェクトで定義されたメイン関数を実行するには、scalaライブラリが必要になる場合があります。また、プロジェクトに外部ライブラリを追加する場合、libraryDependenciesキーに依存関係を追加することで含めることができます。

libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.3")

たとえば、プロジェクトにjson4sライブラリを含めることができます。プロジェクトでサポートするjson4sに関連するjarファイルも、sbt-Assemblyによって生成される最終的なjarファイルに追加されます。つまり、sbtでAssemblyを呼び出すと、プログラムを実行するためのすべての要件を含む1つのjarファイルが生成されるため、プログラムを実行するために別の依存関係を必要としません。

Sbt ShellでAssemblyコマンドをプロンプトすると、ターゲットディレクトリに1つのjarファイルが生成されます。この場合、app-Assembly-1.0.jarはapp/target/scala-2.11ディレクトリにあります。 jarファイルの内部を見ると、多くのクラスが含まれていることがわかります。

$vi  projectDirectoy/target/scala-2.11/app_2.11-1.0.jar
ETA-INF/MANIFEST.MF
scala/
scala/annotation/
scala/annotation/meta/
scala/annotation/unchecked/
scala/beans/
scala/collection/
scala/collection/concurrent/
scala/collection/convert/
scala/collection/generic/
scala/collection/immutable/
scala/collection/mutable/
scala/collection/parallel/
scala/collection/parallel/immutable/
scala/collection/parallel/mutable/
scala/collection/script/
scala/compat/
scala/concurrent/
scala/concurrent/duration/
scala/concurrent/forkjoin/
scala/concurrent/impl/
scala/concurrent/util/
scala/io/
scala/math/
scala/ref/
scala/reflect/
scala/reflect/macros/
scala/reflect/macros/internal/
scala/runtime/
scala/sys/
scala/sys/process/
scala/text/
scala/util/
scala/util/control/
scala/util/hashing/
scala/util/matching/
AppBar$.class
AppBar.class
AppFoo$.class
AppFoo.class
......

前述のように、アセンブリによって生成されたjarファイルには、scalaなどのすべての依存関係と、jarでプログラムを実行するための外部ライブラリが含まれているため、AppFooオブジェクトで定義されたメイン関数を呼び出して、 AppBarオブジェクト。

jaehyuk@ubuntu:~/work/sbt/app/target/scala-2.11$ Java -cp './*' AppFoo
Hello World, I am AppFoo
jaehyuk@ubuntu:~/work/sbt/app/target/scala-2.11$ Java -cp './*' AppBar
Hello World, I am AppBar

ええ〜生成されたjarファイルを使用してmain関数を実行できます。

sbt-pack

sbt-packはsbt-Assemblyとほとんど同じです。プロジェクトが依存するすべてのライブラリを、プログラムの実行に必要なjarファイルとして保存します。ただし、sbt-packはすべての依存関係を1つのjarファイルに統合するのではなく、1つのライブラリの依存関係とクラス(AppFoo.classなど)に対応する複数のjarファイルを生成します。

また、興味深いことに、scalaソースファイルとMakefileで定義されているすべての主要な関数を呼び出してプログラムをインストールするためのスクリプトを自動的に生成します。 sbtシェルでpackコマンドをプロンプトした後に作成されたpackディレクトリを見てみましょう。

jaehyuk@ubuntu:~/work/sbt/app/target/pack$ ls
bin  lib  Makefile  VERSION
jaehyuk@ubuntu:~/work/sbt/app/target/pack$ ls bin/
app-bar  app-bar.bat  app-foo  app-foo.bat
jaehyuk@ubuntu:~/work/sbt/app/target/pack$ ls lib/
app_2.11-1.0.jar  sbt_2.12-0.1.0-SNAPSHOT.jar  scala-library-2.11.12.jar
jaehyuk@ubuntu:~/work/sbt/app/target/pack$ 

上記のように、2つのディレクトリと2つのファイルが作成されます。 binには、ソースで定義された関数を実行するためのすべてのスクリプトファイルが含まれています(各ファイルは、scalaファイルで定義されたメインメソッドの実行に役立つスクリプトです)。 libには、プログラムを実行するために必要なすべてのjarファイルが含まれています。最後に、Makefileを使用して、プログラムと依存ライブラリをシステムにインストールできます。

詳細は各プラグインのgithubページをご覧ください。

13
Jaehyuk Lee