Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Bootstrapping" with Cabal

Tags:

haskell

cabal

Imagine an Makefile like the following:

stage1 : Stage1.hs
       ghc -o stage1 Stage1.hs
Stage1.hs : stage0 
       stage0 > Stage1.hs
stage0 : Stage0.hs
       ghc -o stage0 Stage0.hs

The current directory would contain Makefile and Stage0.hs at first,and produce stage1.

Here are the questions:

  1. How can I do the above entirely within Cabal? Am I supposed to do this only with hooks? (like this or this.) What if the hook must depend on another program in the package to be built?
  2. What if Setup.hs becomes complicated enough that it requires its own dependency management?
  3. Is there a cabalized package that does similar things? If Happy included a cabalized test program that depended on Happy invocation, that would have been a perfect example.
like image 582
mnish Avatar asked Feb 16 '12 16:02

mnish


1 Answers

Cabal is tricky when it comes to situations like these.

As you said, if you can squeeze everything into Setup.hs, you'll keep the number of headaches you'll get to a minimum.

If you have really complicated preprocessors, I would suggest doing this:

  1. Make one cabal package for each preprocessor, with its own dependencies etc. So, for stage0, you would have a cabal file like this:

    Name:
      mypackage-stage0
    Version:
      0.1
    -- ...
    
    Executable mpk-stage0
      Default-language:
        Haskell2010
      Main-is:
        Stage0.hs
      -- ...
    
  2. For stage1, you need to generate the source code, so add a preBuild hook in your Setup.hs for mypackage-stage1 that runs the mpk-stage0 executable:

    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
      }
    

    You'd then add a build-tool dependency on the previous stage:

    Executable mpk-stage1
      -- ...
      Main-is:
        Stage1.hs
      Build-tools:
        mypackage-stage0
    

    This should work in recent cabal versions; otherwise, you might have to add a Build-depends: dependency instead.

  3. You will need to rebuild each package in turn every time you do a cascading change (This is necessary because cabal doesn't manage cross-project dependency changes), so you need a script that does for project in mypackage-stage0 mypackage-stage1; do (cd $project; cabal install); done or something similar.

Cabal was never built for this kind of project, so it will be tricky if you want to do something like this. You should look into using Template Haskell instead if you want to generate code in a more coherent way.

like image 108
dflemstr Avatar answered Sep 29 '22 17:09

dflemstr