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

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Vulnerabilities – Threatpost
Cloudbric
Cloudbric
G
GRAHAM CLULEY
S
Securelist
Schneier on Security
Schneier on Security
Help Net Security
Help Net Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Project Zero
Project Zero
Spread Privacy
Spread Privacy
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
T
Tailwind CSS Blog
博客园_首页
有赞技术团队
有赞技术团队
Simon Willison's Weblog
Simon Willison's Weblog
Stack Overflow Blog
Stack Overflow Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Latest news
Latest news
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Attack and Defense Labs
Attack and Defense Labs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
O
OpenAI News
J
Java Code Geeks
T
Tenable Blog
K
Kaspersky official blog
AWS News Blog
AWS News Blog
S
Security @ Cisco Blogs
The GitHub Blog
The GitHub Blog
T
Threatpost
月光博客
月光博客
H
Heimdal Security Blog
Security Latest
Security Latest
The Hacker News
The Hacker News
Y
Y Combinator Blog
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
C
Cisco Blogs
美团技术团队
Microsoft Security Blog
Microsoft Security Blog
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
C
CERT Recently Published Vulnerability Notes
D
Docker
Google Online Security Blog
Google Online Security Blog
D
DataBreaches.Net
V
Visual Studio Blog
H
Help Net Security

愤鸟杂记

最近一年的小结 - 愤鸟杂记 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