惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Schneier on Security
The Last Watchdog
The Last Watchdog
Cyberwarzone
Cyberwarzone
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cyber Attacks, Cyber Crime and Cyber Security
L
Lohrmann on Cybersecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 司徒正美
The Cloudflare Blog
V
V2EX
博客园_首页
博客园 - 聂微东
Vercel News
Vercel News
人人都是产品经理
人人都是产品经理
G
GRAHAM CLULEY
T
Tenable Blog
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
SecWiki News
SecWiki News
博客园 - 三生石上(FineUI控件)
S
Secure Thoughts
N
News | PayPal Newsroom
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
T
Troy Hunt's Blog
博客园 - 【当耐特】
Forbes - Security
Forbes - Security
H
Hacker News: Front Page
A
About on SuperTechFans
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
D
DataBreaches.Net
P
Privacy & Cybersecurity Law Blog
Schneier on Security
Schneier on Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
D
Docker
P
Proofpoint News Feed

愤鸟杂记

最近一年的小结 - 愤鸟杂记 S70 的3dmark跑分记录计划 - 愤鸟杂记 摩尔线程MTT S70 个人简测 - 愤鸟杂记 谈改编作品时是否应该扯上原作? - 愤鸟杂记 小皋观察记录 - 愤鸟杂记 简单统计下此花亭简中59话出现的一些角色 - 愤鸟杂记 个人向arch linux壁纸自动切换脚本 - 愤鸟杂记 如何让你的组员破防 - 愤鸟杂记 思考马逆第416期睡前消息 - 愤鸟杂记
萌新如何用sbt插件打包一个不需要scala环境的scala程序 - 愤鸟杂记
作者: 愤鸟先飞 · 2023-08-03 · via 愤鸟杂记

本文是我学习scala3过程中的笔记,同时也尽量给scala基础薄弱的读者较好的阅读体验,因此可能会比较啰嗦。

intro

scala是一个多范式的编程语言,提供面向对象编程(OOP)和函数式编程(FP)两种编程范式。scala是一门静态类型的语言,同时具有优秀的类型推断,这使其编写体验又有些类似于动态类型的语言(如Pyhton)。

scala运行在jvm之上,但有具有一些jvm不具备的特性,因此如要运行scala程序,需要系统同时安装jvm和scala。

但同时具备两种运行环境的电脑不多,至少scala环境在大部分电脑中都不存在。那么,很自然的产生了这样的需求:打包scala环境,使整个程序仅需要jvm环境(或者说安装jre),甚至不需要特殊的环境即可运行。代价仅仅是打包的大小有少许增加。
(至于把jvm也打包进来……大概可以试试java打包运行环境的方法)

准备

系统环境

要打包不需要scala环境的scala程序,需要先进行以下的环境准备工作:

  • 配置jdk环境
  • 配置scala环境(要求具备sbt)
    配置环境的步骤不是本文的重点,因此不赘述。

项目配置

在准备好环境之后,就是检查你要打包的项目,其中除了你的代码,最重要的是 build.sbt。这个文件可能长这样:

val scala3Version = "3.3.0"

lazy val root = project
  .in(file("."))
  .settings(
    name := "example",
    version := "0.1.0-SNAPSHOT",

    scalaVersion := scala3Version,

    libraryDependencies += "org.scalameta" %% "munit" % "0.7.29" % Test,
  )

打包成jar

在检查好环境和项目配置后,就需要准备打包需要的工具了。要打包成jar,我们需要的工具是:sbt-assembly

要使用这个工具,需要在 [你的项目根目录]/project/ 里面,添加或编辑 plugins.sbt,内容如下:

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

之后,在 build.sbt 里, .settings() 内,添加一行:

    assembly / mainClass := Some("Package.Main")

其中, "Package.Main" 中的 Package 为你的包路径, Main 为你的主类。

在完成以上工作后,再在你的项目根目录运行如下命令:

sbt assembly

scala1.png
打包过程参考,下略。

若配置无误,则可以顺利打包一份不需要scala环境的scala程序,程序将打包成jar包的形式,可以直接使用 java -jar 运行。当然,首次运行时会下载一些必要的文件,会需要一定的时间和较稳定的网络连接。

打包成程序包

更进一步的,我们可以打包成不需要提前安装scala环境的程序包。这里用到的工具为:sbt-native-packager

类似于sbt-assembly,我们首先需要在 [你的项目根目录]/project/ 里面,添加或编辑 plugins.sbt,内容如下:

addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.16")

这里的1.9.16可以手动换成更新的版本。

然后在 build.sbt 里, .settings() 外,添加一行启用该插件:

enablePlugins(JavaAppPackaging)

随后可以在.settings() 内,添加:

maintainer := "YourName"
Compile / mainClass := Some("Package.Main")

若配置无误,就可以运行以下命令生成依赖,依赖文件会放在[你的项目根目录]/target/universal/stage/里。

sbt stage

然后就可以打包成多种类型的包了,其中包括但不限于:ZIP, TAR, EXE, MSI, DEB, RPM。打包好的文件会放在[你的项目根目录]/target/[打包类型]/里。关于打包的类型和其他配置细节,可以参考这个页面

以下列举几个打包指令:

tzx包:sbt universal:packageXzTarball

exe(需要安装WIX):sbt windows:packageBin

创建不依赖java环境的包

截止目前,我们打包的程序虽然不需要scala环境,但仍需要jre(java环境)。接下来,我们开始尝试打内置jre,不需要提前在系统中安装jre的包。(注:由于我的电脑有完整java环境,因此本部分内容笔者不保证完全可用)

在这里的打包工具仍是sbt-native-packager。

首先,我们需要保证我们的jre版本为jre11或更高。然后,我们需要在 build.sbt 里, .settings() 外,添加如下内容:

enablePlugins(JlinkPlugin)
jlinkIgnoreMissingDependency := JlinkIgnore.only(
  "scala.quoted" -> "scala",
  "scala.quoted.runtime" -> "scala"
)

然后就可以打unversal类型的包了:

sbt universal:packageBin

性能对比

分别用sbt默认方式和以上介绍的方式打包同一份跑分程序代码,并运行3次。

这是sbt打包:
scala3.png

这是sbt-assembly打包:
scala2.png

这是sbt-native-packager打包的不带jre的包:
scala4.png

这是sbt-native-packager打包的带jre的包:
scala5.png

从运行结果可以看出,跑分的差别不大,甚至比笔电拔掉电源适配器产生的影响更小,因此可以认为打包方式对运行性能没有影响。

只是……体积的变化就比较容易感知了。

小结

不同的打包方式各有利弊,在性能差不多的情况下,直接用sbt打包的文件体积最小,但环境要求最高;而自带java环境的包具有最好的跨平台能力,但包体较大。因此要打成什么样的包,应该根据需求决定。

参考文章

https://www.baeldung.com/scala/package-app