为什么在 SBT Play 框架项目中调用 "run" 时 "compile" 被调用了 2 次

Why is "compile" called 2 times when calling "run" in SBT Play Framework Project

在我使用 SBT 的游戏框架项目中,我试图在 compile 任务之前 运行 自定义任务。这可以通过在 build.sbt.

中添加来轻松完成
lazy val hello = taskKey[Unit]("says hello to everybody :)")

hello := {
  println("hello, world")
}

(compile in Compile) := ((compile in Compile) dependsOn hello).value

当我执行 sbt compile 时,它 运行 执行 hello 任务 一次 然后它编译代码。正如预期的那样!

奇怪的是,当我运行sbt run时,hello的任务是运行2次。像这样

(Server started, use Enter to stop and go back to the console...)
hello, world
[info] Compiling 1 Java source to C:\dev\CS\CSBackEnd\target\scala-2.12\classes ...
hello, world
[info] p.a.d.DefaultDBApi - Database [default] initialized
[info] p.a.d.HikariCPConnectionPool - Creating Pool for datasource 'default'

知道如何防止这种情况或至少了解幕后发生的事情吗?在这个例子中,它只是打印一个字符串,但在现实生活中,一个复杂的验证将被调用,它不能 运行 2 次,因为它会花费太多时间。

谢谢

** 编辑 **

这是我执行 sbt inspect tree run.

时的输出
[info] welcome to sbt 1.3.13 (Oracle Corporation Java 1.8.0_201)
[info] loading global plugins from C:\Users\jcote\.sbt.0\plugins
[info] loading settings for project csbackend-build from plugins.sbt ...
[info] loading project definition from C:\dev\CS\CSBackEnd\project
[info] loading settings for project root from build.sbt ...
[info] set current project to S360ControlSite (in build file:/C:/dev/CS/CSBackEnd/)
[info] Compile / run = InputTask[Unit]
[info]   +-Compile / run / mainClass = Task[scala.Option[java.lang.String]]
[info]   +-Global / javaOptions = Task[scala.collection.Seq[java.lang.String]]
[info]   +-baseDirectory =
[info]   | +-thisProject = Project(id root, base: C:\dev\CS\CSBackEnd, configurations: List(compile, runtime, test, provided, optional, web-assets, web-assets-test, web-plugin, universal, universal-docs, universal-src, windows, docker, linux, rpm, debian), plugins: List(org.openapitools.openapistylevalidator..
[info]   |
[info]   +-fileWatchService = play.dev.filewatch.DefaultFileWatchService@205b0b3a
[info]   | +-Global / pollInterval = 500 milliseconds
[info]   | +-Global / sLog = sbt.internal.LogManager$$anon@6531d251
[info]   | +-target = target
[info]   |   +-baseDirectory =
[info]   |     +-thisProject = Project(id root, base: C:\dev\CS\CSBackEnd, configurations: List(compile, runtime, test, provided, optional, web-assets, web-assets-test, web-plugin, universal, universal-docs, universal-src, windows, docker, linux, rpm, debian), plugins: List(org.openapitools.openapistylevalid.. 
[info]   |
[info]   +-playAssetsClassloader = Task[scala.Function1[java.lang.ClassLoader, java.lang.ClassLoader]]
[info]   | +-playAllAssets = Task[scala.collection.Seq[scala.Tuple2[java.lang.String, java.io.File]]]
[info]   |   +-playPrefixAndAssets = Task[scala.Tuple2[java.lang.String, java.io.File]]
[info]   |     +-Web-assets / webPublic = target\web\public\main
[info]   |     | +-assetsTarget = target\web
[info]   |     |   +-target = target
[info]   |     |     +-baseDirectory =
[info]   |     |       +-thisProject = Project(id root, base: C:\dev\CS\CSBackEnd, configurations: List(compile, runtime, test, provided, optional, web-assets, web-assets-test, web-plugin, universal, universal-docs, universal-src, windows, docker, linux, rpm, debian), plugins: List(org.openapitools.openapist.. 
[info]   |     |
[info]   |     +-assetsPrefix = public/
[info]   |
[info]   +-playCommonClassloader = Task[java.lang.ClassLoader]
[info]   | +-Compile / dependencyClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | | +-Compile / dependencyClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | |
[info]   | | +-Compile / externalDependencyClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | | | +-Compile / externalDependencyClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | | | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | | |
[info]   | | | +-Compile / managedClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | | | | +-Global / appConfiguration = xsbt.boot.AppConfiguration@5f22d8ea
[info]   | | | | +-Compile / classpathConfiguration = Task[sbt.librarymanagement.Configuration]
[info]   | | | | | +-Compile / configuration = compile
[info]   | | | | | +-Global / internalConfigurationMap = sbt.Defaults$$$Lambda62/1187225933@797c8f80
[info]   | | | | | +-update = Task[sbt.librarymanagement.UpdateReport]
[info]   | | | | |
[info]   | | | | +-Global / classpathTypes = Set(eclipse-plugin, maven-plugin, bundle, scala-jar, hk2-jar, orbit, test-jar, jar)
[info]   | | | | +-Global / isMetaBuild = false
[info]   | | | | +-Compile / managedClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | | | | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | | | |
[info]   | | | | +-Global / reresolveSbtArtifacts = false
[info]   | | | | +-update = Task[sbt.librarymanagement.UpdateReport]
[info]   | | | | +-Global / useCoursier = true
[info]   | | | |
[info]   | | | +-Compile / unmanagedClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | | |   +-Global / buildDependencies = sbt.internal.BuildDependencies@6c0a821a
[info]   | | |   +-Compile / configuration = compile
[info]   | | |   +-Global / settingsData = Task[sbt.internal.util.Settings[sbt.Scope]]
[info]   | | |   +-thisProjectRef = ProjectRef(file:/C:/dev/CS/CSBackEnd/,root)
[info]   | | |   +-Compile / unmanagedClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | |     +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | | |
[info]   | | +-Compile / internalDependencyClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | |   +-Global / buildDependencies = sbt.internal.BuildDependencies@6c0a821a
[info]   | |   +-Compile / classpathConfiguration = Task[sbt.librarymanagement.Configuration]
[info]   | |   | +-Compile / configuration = compile
[info]   | |   | +-Global / internalConfigurationMap = sbt.Defaults$$$Lambda62/1187225933@797c8f80
[info]   | |   | +-update = Task[sbt.librarymanagement.UpdateReport]
[info]   | |   |
[info]   | |   +-Compile / configuration = compile
[info]   | |   +-Compile / exportedProductJars / transitiveClasspathDependency = ()
[info]   | |   +-Compile / exportedProductJarsIfMissing / transitiveClasspathDependency = ()
[info]   | |   +-Compile / exportedProductJarsNoTracking / transitiveClasspathDependency = ()
[info]   | |   +-Compile / exportedProducts / transitiveClasspathDependency = ()
[info]   | |   +-Compile / exportedProductsIfMissing / transitiveClasspathDependency = ()
[info]   | |   +-Compile / exportedProductsNoTracking / transitiveClasspathDependency = ()
[info]   | |   +-Compile / internalDependencyClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | |   | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   | |   |
[info]   | |   +-Global / settingsData = Task[sbt.internal.util.Settings[sbt.Scope]]
[info]   | |   +-thisProjectRef = ProjectRef(file:/C:/dev/CS/CSBackEnd/,root)
[info]   | |   +-Global / trackInternalDependencies = TrackAlways
[info]   | |
[info]   | +-playCommonClassloader / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |   +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |
[info]   +-playDefaultAddress = 0.0.0.0
[info]   +-playDefaultPort = 9000
[info]   +-playDependencyClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   | +-Runtime / externalDependencyClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   |   +-Runtime / externalDependencyClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |   | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |   |
[info]   |   +-Runtime / managedClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   |   | +-Global / appConfiguration = xsbt.boot.AppConfiguration@5f22d8ea
[info]   |   | +-Runtime / classpathConfiguration = Task[sbt.librarymanagement.Configuration]
[info]   |   | | +-Runtime / configuration = runtime
[info]   |   | | +-Global / internalConfigurationMap = sbt.Defaults$$$Lambda62/1187225933@797c8f80
[info]   |   | | +-update = Task[sbt.librarymanagement.UpdateReport]
[info]   |   | |
[info]   |   | +-Global / classpathTypes = Set(eclipse-plugin, maven-plugin, bundle, scala-jar, hk2-jar, orbit, test-jar, jar)
[info]   |   | +-Global / isMetaBuild = false
[info]   |   | +-Runtime / managedClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |   | | +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |   | |
[info]   |   | +-Global / reresolveSbtArtifacts = false
[info]   |   | +-update = Task[sbt.librarymanagement.UpdateReport]
[info]   |   | +-Global / useCoursier = true
[info]   |   |
[info]   |   +-Runtime / unmanagedClasspath = Task[scala.collection.Seq[sbt.internal.util.Attributed[java.io.File]]]
[info]   |     +-Global / buildDependencies = sbt.internal.BuildDependencies@6c0a821a
[info]   |     +-Runtime / configuration = runtime
[info]   |     +-Global / settingsData = Task[sbt.internal.util.Settings[sbt.Scope]]
[info]   |     +-thisProjectRef = ProjectRef(file:/C:/dev/CS/CSBackEnd/,root)
[info]   |     +-Runtime / unmanagedClasspath / streams = Task[sbt.std.TaskStreams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |       +-Global / streamsManager = Task[sbt.std.Streams[sbt.internal.util.Init$ScopedKey[_ <: Any]]]
[info]   |
[info]   +-playDevSettings = List()
[info]   +-playInteractionMode = Console Interaction Mode
[info]   +-playMonitoredFiles = Task[scala.collection.Seq[java.io.File]]
[info]   | +-Compile / twirlCompileTemplates / sourceDirectories = List(C:\dev\CS\CSBackEnd\app)
[info]   | | +-Compile / sourceDirectory = app
[info]   | |   +-baseDirectory =
[info]   | |     +-thisProject = Project(id root, base: C:\dev\CS\CSBackEnd, configurations: List(compile, runtime, test, provided, optional, web-assets, web-assets-test, web-plugin, universal, universal-docs, universal-src, windows, docker, linux, rpm, debian), plugins: List(org.openapitools.openapistyleval.. 
[info]   | |
[info]   | +-Global / settingsData = Task[sbt.internal.util.Settings[sbt.Scope]]
[info]   | +-thisProjectRef = ProjectRef(file:/C:/dev/CS/CSBackEnd/,root)
[info]   |
[info]   +-playRunHooks = Task[scala.collection.Seq[play.sbt.PlayRunHook]]
[info]   +-Global / sbtVersion = 1.3.13
[info]   +-Global / state = Task[sbt.State]

我不能告诉你为什么你会看到你正在观察的行为。我可以用 SBT 1.3.13 重现错误。当我使用 SBT 1.4.9 时,自定义任务只运行一次,正如您所期望的那样。