.bat file tidy up plus shake-0.16 compatibility (#392)
[hadrian.git] / src / Hadrian / Oracles / ArgsHash.hs
1 {-# LANGUAGE TypeFamilies #-}
2 module Hadrian.Oracles.ArgsHash (
3 TrackArgument, trackAllArguments, trackArgsHash, argsHashOracle
4 ) where
5
6 import Control.Monad
7 import Development.Shake
8 import Development.Shake.Classes
9
10 import Hadrian.Expression hiding (inputs, outputs)
11 import Hadrian.Target
12 import Hadrian.Utilities
13
14 -- | 'TrackArgument' is used to specify the arguments that should be tracked by
15 -- the @ArgsHash@ oracle. The safest option is to track all arguments, but some
16 -- arguments, such as @-jN@, do not change the build results, hence there is no
17 -- need to initiate unnecessary rebuild if they are added to or removed from a
18 -- command line. If all arguments should be tracked, use 'trackAllArguments'.
19 type TrackArgument c b = Target c b -> String -> Bool
20
21 -- | Returns 'True' for all targets and arguments, hence can be used a safe
22 -- default for 'argsHashOracle'.
23 trackAllArguments :: TrackArgument c b
24 trackAllArguments _ _ = True
25
26 -- | Given a 'Target' this 'Action' determines the corresponding argument list
27 -- and computes its hash. The resulting value is tracked in a Shake oracle,
28 -- hence initiating rebuilds when the hash changes (a hash change indicates
29 -- changes in the build command for the given target).
30 -- Note: for efficiency we replace the list of input files with its hash to
31 -- avoid storing long lists of source files passed to some builders (e.g. ar)
32 -- in the Shake database. This optimisation is normally harmless, because
33 -- argument list constructors are assumed not to examine target sources, but
34 -- only append them to argument lists where appropriate.
35 trackArgsHash :: (ShakeValue c, ShakeValue b) => Target c b -> Action ()
36 trackArgsHash t = do
37 let hashedInputs = [ show $ hash (inputs t) ]
38 hashedTarget = target (context t) (builder t) hashedInputs (outputs t)
39 void (askOracle $ ArgsHash hashedTarget :: Action Int)
40
41 newtype ArgsHash c b = ArgsHash (Target c b)
42 deriving (Binary, Eq, Hashable, NFData, Show, Typeable)
43 type instance RuleResult (ArgsHash c b) = Int
44
45 -- | This oracle stores per-target argument list hashes in the Shake database,
46 -- allowing the user to track them between builds using 'trackArgsHash' queries.
47 argsHashOracle :: (ShakeValue c, ShakeValue b) => TrackArgument c b -> Args c b -> Rules ()
48 argsHashOracle trackArgument args = void $
49 addOracle $ \(ArgsHash target) -> do
50 argList <- interpret target args
51 let trackedArgList = filter (trackArgument target) argList
52 return $ hash trackedArgList