【问题标题】:How should I let Shake know that 'ghc --make' is needed to track changes to haskell files?我应该如何让 Shake 知道需要 'ghc --make' 来跟踪对 haskell 文件的更改?
【发布时间】:2014-02-13 14:01:20
【问题描述】:

我想知道一起使用shake 和ghc --make 的推荐方式。在我的项目中,shake 规则用于将 C 源代码编译成它们的*.o 文件(我称之为cobjects),并且这些对象通过调用ghc --make 链接到我的haskell 程序中。在此命令期间,ghc 会自行确定何时需要重建我的 haskell 文件。

以下示例未正确编写以集成这两个工具。如果.hs 文件发生更改,则重新运行摇动脚本不会重新调用ghc --make。我明白为什么 Shake 不知道要重建,但我不知道推荐的修复方法。

main = shake shakeOptions $ do
  want [main_exe]

  main_exe *> \out -> do
    need cobjects
    cmd "ghc --make" hs_compileFlags cobjects "main.hs"

  cobjects **> ...

【问题讨论】:

  • 问题:当你说“当一个 .hs 文件发生变化时”——你的意思是“当main.hschanges? or are there other .hs files involved? It seems to me that your rules for main_exe`应该在某处有needs "main.hs"
  • 不,我的意思是“当任何 .hs 文件更改时”。如果main.hs 未更改,但main.hs 所依赖的另一个源文件foo.hs 已更改,则ghc --make 命令足够聪明,可以自行确定它必须重新编译main.hs 以及任何其他依赖于@ 987654338@.
  • 部分答案可能是使用 ghc -M 让 ghc 发出依赖信息——有关更多详细信息,请参阅 this。然后,您可以将其合并到 needs 语句中。
  • 不要重新运行ghc --make“当任何.hs 文件更改时”,您不想总是重新运行ghc --make吗?似乎有必要重新链接可执行文件,然后ghc --make 也应该获取对 .hs 文件的任何更改。
  • 是的,我一直想运行ghc --make。它应该在(可能)执行cobjects的规则之后运行

标签: haskell shake-build-system


【解决方案1】:

一般原则是,如果规则运行使用文件的命令,它应该依赖于文件。在您的情况下,您必须 need 所有事情 ghc --make 请求,最简单的方法是使用 ghc -M (生成 Makefile):

main = shake shakeOptions $ do
  want [main_exe]

  main_exe *> \out -> do
    need cobjects
    cmd "ghc -M" hs_compileFlags "main.hs"
    cmd "ghc --make" hs_compileFlags cobjects "main.hs"
    needMakefileDependencies "Makefile"

  cobjects **> ...

needMakefileDependencies 函数在Development.Shake.Util 中。唯一的微妙之处是我在运行命令之后调用needMakefileDependencies ,否则目标文件将不会被创建(你可以通过只过滤@ 中的.hs 文件来解决这个问题) 987654330@ 自己使用parseMakefile)。

【讨论】:

  • 这并不像needing 一切ghc -M 请求那么简单。您还必须安排在每个可能需要重新编译的文件上调用ghc,包括通过CPP 进行的更改、更改的编译标志、模板haskell 的addDependentFileghc -M 不跟踪此),以及包的任何时间db 变了。如果源文件已被删除,还有一些与陈旧的.hi/.o 文件有关的奇怪错误。这些可能与每个项目都不相关,但损坏的构建系统非常令人沮丧,所以了解它们是件好事。
  • 正如@JohnL 所说,addDependentFile 将不起作用,如果ghc-pkg list 的输出发生更改,您可能需要调用ghc --make,这会捕获任何包更改。我认为您不需要对每个文件都调用ghc,因为--make 模式会处理这个问题。陈旧的 .hi/.o 文件不应该有任何错误,即使内容已被删除(除了来自 ghc --make 单独的内容)。
  • 我同意,致电ghc --make 应该会处理与这些问题相关的所有问题。我的意思是,如果你想完全避免ghc --make,这些都是你需要自己管理的问题。
【解决方案2】:

看起来推荐的方法可能是使用“假”规则并在顶部为该规则添加want。这是从这个有用的教程中找到的:

http://blog.jle.im/entry/shake-task-automation-and-scripting-in-haskell

我第一次尝试将此想法应用于我的示例:

main = shake shakeOptions $ do
  want [main_exe, "compile and link hs"]

  main_exe *> \out -> do
    need cobjects

  cobjects **> ...

  "compile and link hs" ~> do
    cmd "ghc --make" hs_compileFlags cobjects "main.hs"

(~>) 函数指定字符串 "compile and link hs" 是规则的名称,而不是文件的名称。

虽然这将始终尝试按照我想要的方式运行新规则,但不幸的是,它会尝试在 main_exe 的规则之前运行该规则,这不是我想要的。

将新规则的需求移到main_exe 的规则中似乎可以解决这个新问题:

main = shake shakeOptions $ do
  want [main_exe]

  main_exe *> \out -> do
    need cobjects
    need ["compile and link hs"]

  cobjects **> ...

  "compile and link hs" ~> do
    cmd "ghc --make" hs_compileFlags cobjects "main.hs"

虽然这可行,但我不明白 Shake 如何决定在第一段代码中运行这两个规则的顺序。

【讨论】:

  • 一般来说,need 来自非虚假规则的虚假规则并不是一个好主意。我怀疑如果您将 need ["compile and link hs"] 替换为 cmd "ghc --make" ... 它会完全一样,这会让您回到问题中的内容。
猜你喜欢
  • 1970-01-01
  • 2010-12-19
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-21
  • 1970-01-01
  • 2015-11-21
相关资源
最近更新 更多