Jonathan Cast
Jonathan Cast

Reputation: 4635

How do I stop GHC from recompiling modules when nothing has changed?

I have the following directory structure:

Most, but not of course all, of this code is written in Global Script, and translated to Haskell by a Haskell program, hsgs2hs.

As such, the code in gsi and gs2hs both depend on the modules from libgs.

Because of somewhat sloppy code organization on my part, the compiler in gs2hs also depends on the front-end modules (parser, type-checker, etc.) from the gsi directory.

Legal aside: If it matters: my code is freely available online, but is not open-source, and its license does not permit redistribution through Hackage. End legal aside.

I can make this directory structure work by running

ghc --make -i../libgs gsi.hs -o gsi

in the gsi directory, and

ghc --make -i../libgs -i ../gsi gs2hs.hs -o gs2hs

in the gs2hs directory.

This has the problem that, every time I do both builds in sequence, GHC recompiles every single module in the libgs directory, and every shared module in the gsi directory, telling me 'flags changed'.

I figure, ok, I should probably be using packages for re-used code in Haskell, right? So I convert libgs to a package:

No joy!

Now, any change to libgs at all - even just adding a new module to it - causes GHC to recompile every module in the gsi directory, telling me the fundamental module GSI.Value has changed. Even though it actually hasn't; the source code for that module and everything it depends on (which isn't much) is unchanged. Just the hash for the package it's coming from has changed.

How do I stop GHC from recompiling the world constantly, and get it to only recompile things when the result can actually be different?

Upvotes: 2

Views: 224

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120711

Add a libgs.cabal file to that directory, listing all the modules as exposed modules.

Ok, good.

Add a libgs/install-all script that runs cabal install --lib --package-env $REPO_ROOT/package.env

Don't do that. As a general rule, never use install --lib. It's usually better to let Cabal figure out when to install libraries. The easiest way is to put the executables in the package itself. You can have both a library: section in the .cabal file as well as arbitrarily many executable: gsi and executable: gs2hs ones.

Alternatively, you can keep libgs a package that doesn't care about executables, but have these in their own package each. Then you don't do any builds in the package directories themselves, but instead put a cabal.project file in your main src directory, saying

packages: ./libgs ./gsi ./gs2hs

Then run cabal new-build in that directory. It'll collectively store the require object files in its .dist-newstyle directory.

Upvotes: 6

Related Questions