避免使用 oracle,或者分离相同类型的 oracle
Avoiding oracle, OR separating oracles of the same type
我有以下情况:
find-deps
是一个非常快运行的外部程序,发现依赖信息,类似于ghc -M
。它的输出是一些文件 deps
.
compile
是一个外部程序,速度很慢运行;与 ghc --make
不同,即使 none 的输入已更改,它也非常慢。
所以想法是添加一个运行s find-deps
生成deps
的Shake规则,将其解析为文件列表srcs
,然后编译规则将 need srcs
确保 compile
仅在 find-deps
发现的任何来源已更改时重新 运行。
棘手的部分是 find-deps
需要 alwaysRerun
来发现新依赖的源文件。所以现在如果 compile
规则依赖 deps
来获取文件列表,它也会 alwaysRerun
。标准的解决方案是使用 oracle:我们可以添加一个 need
s deps
的 oracle 并将其解析为文件列表,然后 compile
规则将首先要求它源文件列表,只有 need
个。所以compile
.
的need
链上没有alwaysRerun
但是,就我而言,我并不是在编写特定的 Shakefile。相反,我正在编写一个可重用的 Rules
库,用户可以使用它来制作自己的主 Shakefile。所以我需要把它打包成类似
的东西
myRules :: FilePath -> Rules ()
myRules dir = do
dir </> "deps" %> \depFile -> do
alwaysRerun
cmd_ (Cwd dir) "find-deps" ["-o", depFile]
dir </> "exe" %> \exeFile -> do
srcs <- askOracle $ Sources dir
need srcs
cmd_ (Cwd dir) "compile" ["-o", exeFile]
但是我应该把 addOracle $ \Sources dir -> ...
部分 need [dir </> "deps"]
并解析它和 return 源文件列表放在哪里?我不能将它放在 rules
中,因为这样,对不同目录的 rules
的两次调用将尝试为同一类型安装 oracle 处理程序两次。而且我不能使 dir
成为 oracle 问题类型的一部分,因为它是一个词级变量,所以我不能将它提升到查询的 Symbol
索引中。
这给我留下了一些超级蹩脚的东西,比如有一个 includeThisOnlyOnce :: Rules ()
用户必须记住在他们的 Shakefile 中只包含一次。
所以我的问题是:
- 有没有办法在不涉及 oracle 的情况下跟踪依赖关系(即避免 运行ning
compile
没有源文件更改)? =67=]
- 或者,有没有办法通过某种方式划分相同类型的神谕,以便我可以将这个
Sources
神谕仅添加到每次单独调用 myRules someDir
?
Is there a way to track dependencies without involving an oracle?
是 - 如果 find-deps
的输出根本没有改变,那么它不会重建 compile
。您可以通过指定 Change
值(例如 ChangeModtimeAndDigest
)来实现,但这是一个全局设置。或者,您可以将 find-deps
的输出放在某个地方,例如 foo.deps.out
,然后调用 copyFileChanged "foo.deps.out" "foo.deps"
,如果文件未更改,则不会更新时间戳。
Is there a way to separate oracles of the same type?
虽然我知道它为什么有用,但并不容易和立即。我可以想到两条可能的途径来解决它:
- 可以添加
addOracleIdempotent
,它会忽略关于重复添加同一个 oracle 的任何错误。这是对 Shake 的一个相当简单的更改(本质上是在 Rules
中设置一个标志以忽略重复项)。
- 或者,您可以尝试将
dir
提升为 type-level 并确保每个 oracle 具有不同的类型。它可能会使您的 API 变得更加复杂并且需要类型魔法。
在所有这些解决方案中,我会使用 copyFileChanged
,因为它简单且本地化。
我有以下情况:
find-deps
是一个非常快运行的外部程序,发现依赖信息,类似于ghc -M
。它的输出是一些文件deps
.compile
是一个外部程序,速度很慢运行;与ghc --make
不同,即使 none 的输入已更改,它也非常慢。
所以想法是添加一个运行s find-deps
生成deps
的Shake规则,将其解析为文件列表srcs
,然后编译规则将 need srcs
确保 compile
仅在 find-deps
发现的任何来源已更改时重新 运行。
棘手的部分是 find-deps
需要 alwaysRerun
来发现新依赖的源文件。所以现在如果 compile
规则依赖 deps
来获取文件列表,它也会 alwaysRerun
。标准的解决方案是使用 oracle:我们可以添加一个 need
s deps
的 oracle 并将其解析为文件列表,然后 compile
规则将首先要求它源文件列表,只有 need
个。所以compile
.
need
链上没有alwaysRerun
但是,就我而言,我并不是在编写特定的 Shakefile。相反,我正在编写一个可重用的 Rules
库,用户可以使用它来制作自己的主 Shakefile。所以我需要把它打包成类似
myRules :: FilePath -> Rules ()
myRules dir = do
dir </> "deps" %> \depFile -> do
alwaysRerun
cmd_ (Cwd dir) "find-deps" ["-o", depFile]
dir </> "exe" %> \exeFile -> do
srcs <- askOracle $ Sources dir
need srcs
cmd_ (Cwd dir) "compile" ["-o", exeFile]
但是我应该把 addOracle $ \Sources dir -> ...
部分 need [dir </> "deps"]
并解析它和 return 源文件列表放在哪里?我不能将它放在 rules
中,因为这样,对不同目录的 rules
的两次调用将尝试为同一类型安装 oracle 处理程序两次。而且我不能使 dir
成为 oracle 问题类型的一部分,因为它是一个词级变量,所以我不能将它提升到查询的 Symbol
索引中。
这给我留下了一些超级蹩脚的东西,比如有一个 includeThisOnlyOnce :: Rules ()
用户必须记住在他们的 Shakefile 中只包含一次。
所以我的问题是:
- 有没有办法在不涉及 oracle 的情况下跟踪依赖关系(即避免 运行ning
compile
没有源文件更改)? =67=]- 或者,有没有办法通过某种方式划分相同类型的神谕,以便我可以将这个
Sources
神谕仅添加到每次单独调用myRules someDir
? - 或者,有没有办法通过某种方式划分相同类型的神谕,以便我可以将这个
Is there a way to track dependencies without involving an oracle?
是 - 如果 find-deps
的输出根本没有改变,那么它不会重建 compile
。您可以通过指定 Change
值(例如 ChangeModtimeAndDigest
)来实现,但这是一个全局设置。或者,您可以将 find-deps
的输出放在某个地方,例如 foo.deps.out
,然后调用 copyFileChanged "foo.deps.out" "foo.deps"
,如果文件未更改,则不会更新时间戳。
Is there a way to separate oracles of the same type?
虽然我知道它为什么有用,但并不容易和立即。我可以想到两条可能的途径来解决它:
- 可以添加
addOracleIdempotent
,它会忽略关于重复添加同一个 oracle 的任何错误。这是对 Shake 的一个相当简单的更改(本质上是在Rules
中设置一个标志以忽略重复项)。 - 或者,您可以尝试将
dir
提升为 type-level 并确保每个 oracle 具有不同的类型。它可能会使您的 API 变得更加复杂并且需要类型魔法。
在所有这些解决方案中,我会使用 copyFileChanged
,因为它简单且本地化。