sbt-pack和sbt-assembly之间的主要区别是什么?

Jac*_*ski 35 sbt sbt-assembly

我刚刚偶然发现了sbt-pack插件.开发流似乎很稳定.令我惊讶的是,我认为(引用sbt-pack的标题)"创建可分发的Scala包"的唯一插件.sbt-assembly(在其他功能中).

插件之间的主要区别是什么?我什么时候应该使用另一个?

Eug*_*ota 68

(免责声明:我维持sbt-assembly)

SBT组装

sbt-assembly创建一个胖JAR - 一个包含代码和库中所有类文件的JAR文件.通过演化,它还包含在多个JAR提供相同文件路径(如config或README文件)时解决冲突的方法.它涉及解压缩所有库JAR,因此它有点慢,但这些都是高度缓存的.

SBT-包

sbt-pack使所有库JAR保持不变,将它们移动到target/pack目录中(而不是通常存在的常春藤缓存),并为您创建一个shell脚本来运行它们.

SBT-本机打包

sbt-native-packager类似于sbt-pack,但它是由一位sbt提交者Josh Suereth创建的,现在由功能强大的Nepomuk Seiler(也称为muuki88)维护.该插件支持多种格式,如Windows msi文件和Debian deb文件.最近增加的是对Docker镜像的支持.

所有这些都是创建部署映像的可行方法.在某些情况下,例如将您的应用程序部署到Web框架等,如果您处理的是一个文件而不是十几个文件,则可能会使事情变得更容易.

荣誉奖:sbt-progardsbt-onejar.

  • @EugeneYokota`sbt package`如何与这些相关? (8认同)

Jae*_*Lee 12

尽管Eugene Yokota的解释已经完成,但我想在使用方面解释所提到的带有package命令的插件以及如何生成不同的结果.

目录设置和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)
Run Code Online (Sandbox Code Playgroud)

上面的build.sbt文件声明了一个名为app的项目,并包含app目录中的所有源文件.要启用Pack插件,enablePlugins(PackPlugin)应该包含在sbt文件中.

另外,我将下面的行放在project/plugins.sbt文件中,以便在我们的项目中使用pack plugins

addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.9.3")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
Run Code Online (Sandbox Code Playgroud)

默认情况下,该包已经集成到sbt中,因此您不必使用addSbtPlugins显式指定插件.但是,sbt-pack和sbt-assembly插件默认情况下不包含在sbt中,因此您必须指定要使用它们.addSbtPlugin是一种表达"我想在我的项目中使用xxx,yyy插件"的方式给你的sbt.

另外,我在./app/src/main/scala中实现了两个人为设计的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()
  }
}
Run Code Online (Sandbox Code Playgroud)

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()
  }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

请注意,它仅包含从位于app/src/main/scala目录中的scala文件生成的类文件.package命令生成的jar文件不包含任何scala相关库,例如scala库中的集合(例如,collection.mutable.Map.class).因此,要执行该程序,您可能需要scala库,因为生成jar文件仅包含从我实现的scala源生成的最小类.这就是为什么jar文件包含AppBar.class,AppBar $ .class用于伴随对象等的原因.

SBT组装

正如Eugene Yokota所提到的,sbt-assembly还可以帮助您通过生成jar文件来分发项目; 但是生成的jar文件不仅包括源代码生成的类文件,还包括执行程序所需的所有库.例如,要执行AppFoo对象中定义的main函数,您可能需要scala库.此外,在项目中添加外部库时,可以通过将依赖项添加到libraryDependencies键来包含外部库.

libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.3")
Run Code Online (Sandbox Code Playgroud)

例如,您可以在项目中包含json4s库,并且与项目中支持json4相关的jar文件也将添加到sbt-assembly生成的最终jar文件中.换句话说,当你在sbt中调用程序集时,它会生成一个包含执行程序所有需求的jar文件,这样你就不需要另外一个依赖来执行你的程序了.

当您在sbt shell中提示汇编命令时,它将在目标目录中生成一个jar文件.在这种情况下,您可以在app/target/scala-2.11目录中找到app-assembly-1.0.jar.当您查看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
......
Run Code Online (Sandbox Code Playgroud)

如前所述,由于程序集生成的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
Run Code Online (Sandbox Code Playgroud)

是的〜你可以使用生成的jar文件执行main函数.

SBT-包

sbt-pack与sbt-assembly几乎相同; 它将项目所依赖的所有库保存为执行程序所需的jar文件.但是,sbt-pack没有将所有依赖项集成到一个jar文件中,而是生成多个jar文件,这些文件对应于一个库依赖项和您的类(例如,AppFoo.class).

另外,有趣的是它会自动生成脚本,用于调用scala源文件和Makefile中定义的所有主要函数来安装程序.让我们看一下在sbt shell上提示打包命令后创建的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$ 
Run Code Online (Sandbox Code Playgroud)

如上所示,创建了两个目录和两个文件; bin包含执行源中定义的函数的所有脚本文件(每个文件都是一个脚本,可以帮助您执行scala文件中定义的main方法); lib包含执行程序所需的所有jar文件; 最后,Makefile可用于在系统中安装程序和依赖库.

有关详细信息,请参阅每个插件的github页面.