sbt组件和sbt组件之间的主要区别是什么?

sbt组件和sbt组件之间的主要区别是什么?,sbt,sbt-assembly,Sbt,Sbt Assembly,我刚刚偶然发现了这个插件。发展趋势似乎是如此。这让我感到惊讶,因为我相信(引用sbt pack的标题)“创建可分发的Scala软件包”的唯一插件是(在其他功能中) 插件之间的主要区别是什么?什么时候我应该使用一个而不是另一个?(免责声明:我维护sbt组件) sbt组件 创建一个fat JAR—一个包含代码和库中所有类文件的JAR文件。通过演化,它还包含解决多个JAR提供相同文件路径(如配置或自述文件)时冲突的方法。它需要解压所有的库jar,所以速度有点慢,但这些都被大量缓存 sbt包 保持所有库

我刚刚偶然发现了这个插件。发展趋势似乎是如此。这让我感到惊讶,因为我相信(引用sbt pack的标题)“创建可分发的Scala软件包”的唯一插件是(在其他功能中)

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

(免责声明:我维护sbt组件)

sbt组件 创建一个fat JAR—一个包含代码和库中所有类文件的JAR文件。通过演化,它还包含解决多个JAR提供相同文件路径(如配置或自述文件)时冲突的方法。它需要解压所有的库jar,所以速度有点慢,但这些都被大量缓存

sbt包 保持所有库jar的完整性,将它们移动到
target/pack
目录中(与它们通常所在的常春藤缓存相反),并生成一个shell脚本供您运行它们

本机包装机 类似于sbt包,但它是由sbt提交人启动的,现在由High Capability(也称为muuki88)维护。该插件支持多种格式,如Windows msi文件和Debian deb文件。最近添加的内容支持

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


荣誉奖:和。

虽然Eugene Yokota的解释是完整的,但我想用package命令解释所提到的插件的用法以及如何产生不同的结果

目录设置和build.sbt 上面的build.sbt文件声明了名为app的项目,并包括app目录中的所有源文件。要启用包插件,sbt文件中应包含enablePlugins(PackPlugin)

另外,我在项目/plugins.sbt文件中放了下面一行,以便在我们的项目中使用包插件

addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.9.3")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
默认情况下,该包已经集成到sbt中,因此您不必使用addSbtPlugins显式指定插件。但是,默认情况下sbt中不包括sbt包和sbt程序集插件,因此您必须指定要使用它们。addSbtPlugin是对您的sbt说“我想在我的项目中使用xxx,yyy插件”的一种方式

另外,我在./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()
  }
}
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()
  }
}
AppFoo.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()
  }
}
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中的源代码的结果。此外,它还包括一个清单文件

$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文件生成的类文件。package命令生成的jar文件不包括任何与scala相关的库,例如scala库中的collection(例如collection.mutable.Map.class)。因此,要执行该程序,您可能需要scala库,因为generate jar文件只包含从我实现的scala源代码生成的最小类。这就是jar文件包含AppBar.class、AppBar$.class作为伴随对象等的原因

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

libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.3")
例如,您可以在项目中包含json4s库,并且与项目中支持json4s相关的jar文件也将添加到sbt程序集生成的最终jar文件中。换句话说,当您在sbt中调用assembly时,它会生成一个jar文件,其中包含执行程序的所有需求,因此您不需要另一个依赖项来执行程序

当您在sbt shell中提示assembly命令时,它将在您的目标目录中生成一个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
......
如前所述,由于程序集生成的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文件执行主功能

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

另外,有趣的是,它会自动生成脚本,用于调用scala源文件和Makefiles中定义的所有主要函数来安装程序。让我们来看一下在你的SBT shell上提示打包命令后创建的包目录。
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$