与Cabal一起"引导"

mni*_*ish 8 haskell cabal

想象一下如下的Makefile:

stage1 : Stage1.hs
       ghc -o stage1 Stage1.hs
Stage1.hs : stage0 
       stage0 > Stage1.hs
stage0 : Stage0.hs
       ghc -o stage0 Stage0.hs
Run Code Online (Sandbox Code Playgroud)

当前目录首先包含Makefile和Stage0.hs,并生成stage1.

以下是问题:

  1. 我怎样才能完全在Cabal中完成上述操作?我应该只用挂钩做这件事吗?(像这样或者这样.)如果钩子必须依赖于要构建的包中的另一个程序,该怎么办?
  2. 如果Setup.hs变得复杂到需要自己的依赖关系管理怎么办?
  3. 是否有一个类似的东西的cabalized包?如果Happy包含一个依赖于Happy调用的cabalized测试程序,那将是一个很好的例子.

dfl*_*str 5

对于像这样的情况,Cabal很棘手.

正如你所说,如果你能把所有东西都挤进去Setup.hs,你就会把头疼的次数降到最低.

如果您有非常复杂的预处理器,我建议这样做:

  1. 为每个预处理器创建一个cabal包,具有自己的依赖项等.因此,对于stage0,您将拥有如下的cabal文件:

    Name:
      mypackage-stage0
    Version:
      0.1
    -- ...
    
    Executable mpk-stage0
      Default-language:
        Haskell2010
      Main-is:
        Stage0.hs
      -- ...
    
    Run Code Online (Sandbox Code Playgroud)
  2. 因为stage1,您需要生成源代码,因此preBuild在您的Setup.hsfor mypackage-stage1中添加一个运行mpk-stage0可执行文件的钩子:

    main =
      defaultMainWithHooks simpleUserHooks
      { preBuild =
          -- ... something involving `system "mpk-stage1 Stage1.hs"`
          -- Note that shell redirection `> bla.hs` doesn't necessarily work
          -- on all platforms, so make your `mpk-stage1` executable take an
          -- output file argument
      }
    
    Run Code Online (Sandbox Code Playgroud)

    然后,您将在上一阶段添加构建工具依赖项:

    Executable mpk-stage1
      -- ...
      Main-is:
        Stage1.hs
      Build-tools:
        mypackage-stage0
    
    Run Code Online (Sandbox Code Playgroud)

    这应该适用于最近的cabal版本; 否则,您可能必须添加Build-depends:依赖项.

  3. 每次进行级联更改时,您需要依次重建每个包(这是必要的,因为cabal不管理跨项目依赖项更改),因此您需要一个for project in mypackage-stage0 mypackage-stage1; do (cd $project; cabal install); done类似的脚本.

Cabal从来就不是为这种项目而建的,所以如果你想做这样的事情很棘手.如果您想以更连贯的方式生成代码,则应该考虑使用Template Haskell.

  • 可悲的是,你无法制作临时可执行文件.模板Haskell可以在多个阶段使用; 您可以使用TH生成生成Haskell代码的TH代码.如果您认为您的答案会对其他人有所帮助,那么您应该发布自己的答案. (2认同)