控制 SBT 多项目上的依赖项加载歧义

Posted

技术标签:

【中文标题】控制 SBT 多项目上的依赖项加载歧义【英文标题】:Control dependency loading ambiguity on SBT multi-project 【发布时间】:2015-12-29 22:27:51 【问题描述】:

我有一个 SBT Scala 多项目,其结构如下:

multiprojectRoot        
    project/SharedProjectBuildCode.scala
    project1
        src/sourceFiles
        project1-build.sbt
    project2
        src/sourceFiles
        project2-build.sbt
    projectN
        src/sourceFiles
        projectN-build.sbt

multiprojectRoot/project/SharedProjectBuildCode.scala:包含使用dependsOn创建本地项目依赖的多项目定义。例如:

lazy val project2 = Project(
    ...
).dependsOn(project1)

multiprojectRoot/project2/project2-build.sbt:包含给定项目的设置和依赖项。例如:

name := "project2"

libraryDependencies ++= Seq(          
          ...
          "my.company" % "project1" % "1.0"
)

对 project1 的第一个依赖项是在 SharedProjectBuildCode.scala 文件上使用 dependsOn 声明的,第二个是在独立的 project2-build.sbt 构建定义文件上创建的。

所以,project2 定义包含:

对 project1 或 的模糊依赖 对 project1 的双重依赖

我们希望保持这个项目结构,因为它最适合我们当前的工作流程:

独立的 .sbt 文件用于我们持续交付服务器上的每个项目的独立部署。 带有dependsOn的多项目.scala文件用于方便开发,让我们避免连续publishLocal之类的事情。

我们需要以某种方式控制这种依赖模糊。你能帮助我吗?

【问题讨论】:

【参考方案1】:

我认为你应该在SharedProjectBuildCode.scala

lazy val root = Project(id = "Main-Project",
    base = file(".")) aggregate(project1, project2,..)

lazy val project2 = Project(id = "project2",
    base = file("project1")).dependsOn(project1)

...

并且不再需要在 build.sbt 中添加依赖项。

【讨论】:

谢谢泰勒。问题是我们希望将独立的 .sbt 文件也保留为独立的,以用于部署目的。 DependsOn 应该用于开发,而独立项目构建将用于在我们的持续交付服务器上部署。 我认为你可以在没有多模块项目的情况下实现它。只需将它们全部设为独立项目并使用 sbt publish-local 构建,然后 libraryDependencies 应该在 sbt 文件中按预期工作。 嗯,publishLocal 正是我们希望在非部署开发周期中避免的。由于项目之间共享大量代码,因此必须为共享代码的每次更改执行手动步骤来 publishLocal 会真正减慢我们的速度,并使过程更加手动控制。一定有办法解决这个问题。 有两个 build.sbt 版本,一个用于生产,带有 libraryDependencies,另一个没有它,这样您就可以摆脱双重依赖。 是的,这将是最后的解决方案。我现在要尝试的只是为项目的独立构建添加“增量”属性,通过添加项目构建定义文件进行部署。它有效,我将其作为解决方案发布。【参考方案2】:

通过使用 SBT 提供的构建文件加载规则,我能够控制在每个用例上加载的依赖集。

当您从给定的根目录加载 SBT 时,它会在根目录中查找 *.sbt 文件,并在根/项目目录中查找 *.scala。如果你有一个多项目构建,那么它也会读取在子项目上遇到的 .sbt 文件的定义,但它不会在子项目上使用 project/.scala 文件:

.sbt build definition

Multi-project builds

所以,我通过以下方式更改了我的多项目构建:

multiprojectRoot        
    project/SharedProjectBuildCode.scala
    project1
        src/sourceFiles
        project/DeploymentOnlyCode.scala
        project1-build.sbt
    project2
        src/sourceFiles
        project/DeploymentOnlyCode.scala
        project2-build.sbt
    projectN
        src/sourceFiles
        project/DeploymentOnlyCode.scala
        projectN-build.sbt

这样,根据我从多项目根目录或项目内部目录运行 SBT 的用例:

开发:SBT 从 multiprojectRoot 目录运行。它利用了多项目构建的优势(例如使用dependsOn 和避免publishLocal)。 生产:SBT 在具体项目目录中运行,例如 multiprojectRoot/project2。它允许将项目构建为独立的,将所有依赖项都作为显式的外部依赖项(用于声明对生产、持续集成服务器的一系列依赖项)。

现在,一个项目有 3 个代码实例,它们为最终构建聚合它们的属性:

    multiprojectRoot/project/SharedProjectBuildCode.scala:包含与多项目构建相关的本地依赖项和其他代码。 multiprojectRoot/project1/project1-build.sbt:包含项目构建属性,常见于项目的多项目和独立构建,例如始终外部的名称或依赖项。对于同级别的其他多项目项目也应该这样做,以明确地视为外部依赖项。 multiprojectRoot/project1/project/DeploymentOnlyCode.scala:包含仅在独立构建时才会考虑的构建属性。如果其他子项目需要定义部署特定属性,也可以这样做。

这还可以最大程度地控制项目的构建方式,是否是可发布的工件,并将仅与给定项目相关的源代码作为完整且独立的部分处理。

【讨论】:

以上是关于控制 SBT 多项目上的依赖项加载歧义的主要内容,如果未能解决你的问题,请参考以下文章

如何在 sbt 项目中使用 sbt 插件作为库依赖项?

SBT:多构建依赖/聚合项目中的覆盖设置

SBT 多项目中未解决的依赖关系

sbt 插件和使用插件本身的多项目构建中的项目之间的相互依赖关系

SBT/Play2 多项目设置在运行/测试的类路径中不包括依赖项目

多项目中的SBT测试依赖性:使测试代码可用于相关项目