I have a Haskell program that I want to compile with GHC, orchestrated by the Shake build system. Which commands should I execute, and under what circumstances should they be rerun?
1 Answers
There are two approaches to doing the compilation, and two approaches to getting the dependencies. You need to pick one from each set (all 4 combinations make sense), to come up with a combined approach.
Compilation
You can either:
- Call
ghc -con each file in turn, depending on the.hsfile and any.hifiles it transitively imports, generating both a.hiand.ofile. At the end, callghc -odepending on all the.ofiles. For actual code see this example. - OR Call
ghc --makeonce, depending on all.hsfiles. For actual code see this example.
The advantage of ghc --make is that it is faster than multiple calls to ghc -c since GHC can load each .hi file only once, instead of once per command. Typically the speedup is 3x. The disadvantage is parallelism is harder (you can use -j to ghc --make, but Shake still assumes each action consumes one CPU), and that two ghc --make compilations can't both run at the same time if they overlap on any dependencies.
Dependencies
You can either:
- Parse the Haskell files to find dependencies recursively. To parse a file you can either look for
importstatements (and perhaps#includestatements) following a coding convention, or use a library such ashaskell-src-exts. For actual code with a very approximateimportparser see this example. - OR Use the output of
ghc -Mto detect the dependencies, which can be parsed using the Shake helper functionparseMakefile. For actual code see this example.
The advantage of parsing the Haskell files is that it is possible to have generated Haskell files and it can be much quicker. The advantage of using ghc -M is that it is easier to support all GHC features.
- 9,090
- 1
- 27
- 85
-
2It's great that you post this here, but strictly speaking this doesn't conform with SO policy because only the external code examples answer the question. I think you should embed the crucial rules in the post. – leftaroundabout Jun 08 '18 at 10:54
-
1Thanks @leftaroundabout - I expanded the answers so now the bullet points completely answer the question in enough detail - which is probably way more useful. The code is still linked, but it's not the answer, and it's mostly so people who understand the answer can copy it more easily. I don't want to reproduce the full code in SO since it detracts from the understanding of the answer. – Neil Mitchell Jun 08 '18 at 11:17