-
Notifications
You must be signed in to change notification settings - Fork 123
Description
This is in the context of ghcide, but is more of a general query on how to accomplish this sort of thing with shake, so I'm asking here.
A bit of background first -
- Compilation via GHC can be run in two modes, either we can just typecheck, producing a
ModIface
, or we can go all the way and do code-gen, producing aLinkable
. - This process can't be resumed - we can't go from a
ModIface
to aLinkable
, we need to redo the entire compilation pipeline in order to produce aLinkable
- We only need
Linkables
for modules that are depended on by something that uses TemplateHaskell - So, we have a rule called
NeedsCompilation
which analyses the the reverse dependencies of a module to check if we need to do code-gen. It returnsTrue
if this is the case, orFalse
if we can stop after generating theModIface
. - The
GetModIface
rule generates a pair(ModIface, Maybe Linkable)
, where the invariant is that theLinkable
is guaranteed to be present ifNeedsCompilation
returned true. (NeedsCompilation
is a dependency ofGetModIface
)
All this seems to have been working fine. However, the complication is introduced with the eval plugin.
To evaluate an expression in the context of a module, we must have Linkable
s for it and all of its dependencies.
A first approach at supporting this can be:
- When evaluating an expression in the context of a file, somehow mark the file as needing compilation in some global state.
- Make
NeedsCompilation
consult this bit of global state when it makes a decision. - Restart the shake build
- If all went well, we would have all the
Linkables
we require, and we can evaluate the expression - Reset the global state so we don't do unnecessary code-gen on subsequent builds.
This looks reasonable at first, but it means we will just throw away all the Linkable
s we computed for eval on subsequent builds after evaluation, and we will have to rebuild everything, since NeedsCompilation
changed from True
to False
, and it is a dependency of GetModIface
.
Ideally, as long as all dependencies of GetModIface
except NeedsCompilation
are unchanged, we would not need to recompute the ModIface
(The extra Linkable
doesn't really hurt, and it could be used by subsequent evaluations). If some dependency of GetModIface
other than NeedsCompilation
did change, then we want to do a rebuild, but without producing a
Linkable
.
Also, we only want to have this behavior when NeedsCompilation
flips from True
to False
. If it flips from False
to True
, then we really do need to rebuild.
While going through the shake documentation, I came across the ChangedStore
constructor of RunChanged
. Its documentation reads "The stored value has changed, but in a way that should be considered identical (used rarely)." which does seem like it somewhat fits this situation. However, I'm still not sure if this is its purpose, and if using it would work in this scenario.
Is something like this possible with the shake model? Is ChangedStore
the way to accomplish this?
/cc @pepeiborra