使用 SBT 进行跨平台构建

Cross platform build with SBT

我目前正在测试 SBT Native Packager,我想要的结果是为每个支持的平台提供一个本地安装程序。显然,要做到这一点,平台特定的 SBT 任务需要在该平台上 运行。

构建将使用 Atlassian 的 Bamboo 或 JetBrains 的 Team City 完成。

理想情况下,我只会进行一次编译和测试,然后将相同的工件重复用于打包任务。

用 SBT 解决这个问题的好方法是什么?

我能想到的一种方法是在任何平台上进行编译和测试,然后将它们发布到本地存储库。然后包会以某种方式使用这些。然而,这也需要更改包装,使其不依赖于编译任务等。

TL;DR 版本: 使用单独的 sbt 项目。

正如您可能注意到的,JDKPackager 插件在各种平台上创建本机包。一次构建和测试主要工件的技巧是将它们发布到工件服务器,然后有一个单独的项目来创建安装程序。

如果您的项目每个平台只需要一个安装程序,那么您需要做的就是添加依赖项,设置 mainClass 键,然后添加 enablePlugins(JDKPackagerPlugin):

enablePlugins(JDKPackagerPlugin)

name := "JDKPackagerPlugin Example"

version := "0.1.0"

organization := "com.foo.bar"

libraryDependencies += "com.foo.bar" %% "myProject" % "0.1.0"

mainClass in Compile := Some("com.foo.bar.ExampleApp")

// Optional: provide application file associations
jdkPackagerAssociations := Seq(
    FileAssociation("foobar", "application/foobar", "Foobar file type"),
    FileAssociation("barbaz", "application/barbaz", "Barbaz file type", jdkAppIcon.value)
)

如果您遇到每个平台需要多个安装程序的情况(例如,命令行工具与 GUI),我通常会构建一个项目,使其具有一个名为 "packaging" 的子目录,其中包含一个独立的 build.xml 文件,聚合定义每个安装程序配置的独立子项目:

// Settings common across subprojects. Could also do this with a 
// project-specific `AutoPlugin`
val baseSettings = Seq(
    libraryDependencies += "com.foo.bar" %% "myProject" % "0.1.0"
)

// The packaging aggregation project
lazy val packaging = project
   .in(file("."))
   .aggregate(a, b)

// Project with CLI configuration
lazy val a = Project(id = "my-project-cli", base = file("my-project-cli"))
  .settings(baseSettings: _*)

// Project with GUI configuration    
lazy val b = Project(id = "my-project-gui", base = file("my-project-gui"))
  .settings(baseSettings: _*)

// Create a task for invoking the sub-projects as needed
val packageSubs = taskKey[Seq[File]]("Build packages in subprojects")
(packageSubs in packaging) := {
  Seq(
    (packageBin.in(a, Universal)).value,
    (packageBin.in(b, JDKPackager)).value
  ) 
}

我发现像这样分解安装程序配置有助于保持依赖关系和特定自定义的效果。