使用SBT进行跨平台构建

3
我目前正在测试SBT Native Packager,我的期望结果是为每个支持的平台都生成本地安装程序。显然,为了实现这一点,需要在相应平台上运行特定于该平台的SBT任务。
构建将使用Atlassian的Bamboo或JetBrains的Team City完成。
理想情况下,我只需要编译和测试一次,然后重复使用相同的构件进行打包任务。
有什么好的方法可以用SBT来解决这个问题?
我能想到的一个方法是在任何平台上进行编译和测试,然后将其发布到本地存储库中。然后,打包过程会以某种方式使用这些内容。但是,这也需要更改打包方式,以便它不依赖于编译任务等。

显然,要做到这一点,特定于平台的SBT任务需要在该平台上运行。这绝对不是显而易见的,它是许多打包程序的典型限制,包括SBT本地打包器底层使用的“javapackager”,但是我自己基于Java的打包器可以在Windows下创建本机OS X捆绑包,在Mac OS X下创建GNU Linux DEB&RPM,并在GNU Linux下创建Windows可执行安装程序:http://tuer.sourceforge.net/en/documentation/#jndt 例如,可以在GNU Linux下进行一些持续集成,同时针对Windows和OS X。您可以使用ant4sbt调用JNDT。 - gouessej
1个回答

3

简短版: 使用单独的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
  ) 
}

我发现将安装程序配置分解成这样有助于保持依赖关系和特定自定义的影响清晰易懂。

这是一个非常棒的解决方案,直到我开始使用IntelliJ。现在,除非我在每次提交后进行发布,否则它总是无法加载打包。 - steinybot
有没有在使用 .dependsOn(...) 时出现问题,例如 a.dependsOn(b)。我也使用 IntelliJ,但没有遇到过问题。 - metasim
实际上我的情况有些不同。我有ab生成的JAR文件,这是我的第一个构建计划将要生成和发布的。然后我有单独的平台特定构建,调用packaging/rpm:packageBin等命令,这些命令具有来自ab的工件作为依赖项。因此,除非已经发布了ab,否则packaging/update将失败。 - steinybot
1
我对此感到厌烦,于是深入研究了IntelliJ SBT源代码,并最终找到了sbt-ide-settings。将ideSkipProject := true添加到打包项目中完美解决了问题。 - steinybot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接