【问题标题】:Avoiding oracle, OR separating oracles of the same type避免预言机,或分离相同类型的预言机
【发布时间】:2020-10-09 17:36:00
【问题描述】:

我有以下情况:

  • find-deps 是一个运行速度非常快的外部程序,它可以发现依赖信息,类似于ghc -M。它的输出是一些文件deps
  • compile 是一个运行很慢的外部程序;与ghc --make 不同,即使没有任何输入发生变化,它也非常慢。

所以想法是添加一个运行find-deps的Shake规则以产生deps,将其解析为文件列表srcs,然后编译规则将need srcs确保compile是仅当find-deps 发现的任何源发生更改时才重新运行。

棘手的部分是find-deps 需要alwaysRerun,才能发现新依赖的源文件。所以现在如果compile 规则依赖deps 来获取文件列表,它也将alwaysRerun。标准解决方案是使用 oracle:我们可以添加一个 oracle,needs deps 并将其解析为文件列表,然后 compile 规则将首先询问源文件列表,并且只有need他们。所以compileneed链上没有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]

但是我应该把need [dir &lt;/&gt; "deps"]addOracle $ \Sources dir -&gt; ... 部分放在哪里并解析它并返回源文件列表?我不能把它放在rules 中,因为这样两次使用不同目录的rules 调用将尝试为同一类型安装一个oracle 处理程序两次。而且我不能让 dir 成为 oracle 问题类型的一部分,因为它是一个术语级别的变量,所以我不能将它提升到查询的 Symbol 索引中。

这给我留下了一些超级蹩脚的东西,比如有一个includeThisOnlyOnce :: Rules (),用户必须记住在他们的 Shakefile 中只包含一次。

所以我的问题是:

  • 有没有办法跟踪依赖关系(即避免在没有更改源文件时运行compile不涉及预言机
  • 或者,有没有办法分隔相同类型的预言机,以某种方式确定它们的范围,以便我可以将此Sources oracle 添加到每个单独调用myRules someDir 的上下文中?

【问题讨论】:

    标签: haskell build dependencies shake-build-system


    【解决方案1】:

    有没有办法在不涉及预言机的情况下跟踪依赖关系?

    是的 - 如果find-deps 的输出根本没有改变,那么它就不会重建compile。您可以通过指定Change 值(例如ChangeModtimeAndDigest)来实现这一点,但这是一个全局设置。或者,您可以将find-deps 的输出放在某个位置,例如foo.deps.out,然后调用copyFileChanged "foo.deps.out" "foo.deps",如果文件没有更改,则不会更新时间戳。

    有没有办法区分相同类型的预言机?

    虽然我知道它为什么有用,但并不容易和立即。我可以想到两种可能的解决方法:

    1. 可以添加addOracleIdempotent,它忽略了有关重复添加相同oracle 的任何错误。这是对 Shake 的一个适度简单的更改(基本上是在 Rules 中设置一个标志以忽略重复项)。
    2. 或者,您可以尝试将dir 提升到类型级别并确保每个oracle 具有不同的类型。它可能会使您的 API 更加复杂,并且需要类型魔法。

    在所有这些解决方案中,我会使用copyFileChanged,因为它既简单又本地化。

    【讨论】:

    • 我希望添加一个作用域预言机不会太难,tbh :)
    • 要真正确定范围是不可能的,因为在检查是否需要重新运行时,它们都需要在顶部可用。
    猜你喜欢
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-14
    • 2016-04-18
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    相关资源
    最近更新 更多