Reputation: 27626
Full Shakefile.hs
:
import Development.Shake
import Development.Shake.FilePath
outDir = "_build"
expensiveProcess :: IO ()
expensiveProcess = do
putStrLn "expensiveProcess"
writeFile (outDir </> "b") "b"
main = shakeArgs shakeOptions{ shakeFiles = outDir } $ do
outDir </> "a" %> \out -> do
alwaysRerun
writeFileChanged out "a"
outDir </> "b" %> \out -> do
need [outDir </> "a"]
liftIO expensiveProcess
Let's say I start with an empty _build
directory, and shake _build/b
. In that case, _build/a
has changed (since it's a new file), so we run some expensive process to generate _build/b
:
$ rm -rf _build; stack exec -- shake --trace --trace _build/b
% Starting run
% Number of actions = 1
% Number of builtin rules = 9 [FilesQ,DoesDirectoryExistQ,GetDirectoryContentsQ,AlwaysRerunQ,GetDirectoryDirsQ,DoesFileExistQ,GetDirectoryFilesQ,GetEnvQ,FileQ]
% Number of user rule types = 1
% Number of user rules = 2
% Before usingLockFile on _build/.shake.lock
% After usingLockFile
% Missing -> Running, _build/b
# _build/b
% Missing -> Running, _build/a
# _build/a
% Missing -> Running, alwaysRerun
% Running -> Ready, alwaysRerun
= ((),"") (changed)
% Running -> Ready, _build/a
= ((Just File {mod=0x5F12F628,size=0x1,digest=NEQ},"")) (changed)
expensiveProcess
% Running -> Ready, _build/b
= ((Just File {mod=0x4D7E9358,size=0x1,digest=NEQ},"")) (changed)
Build completed in 0.00s
If I now shake _build/b
again, then expensiveProcess
doesn't run (good!), since its input _build/a
hasn't changed. However, its output is marked as changed
which can cause problems further downstream, if anything else depends on _build/b
:
$ stack exec -- shake --trace --trace _build/b
% Starting run
% Number of actions = 1
% Number of builtin rules = 9 [FilesQ,DoesDirectoryExistQ,GetDirectoryContentsQ,AlwaysRerunQ,GetDirectoryDirsQ,DoesFileExistQ,GetDirectoryFilesQ,GetEnvQ,FileQ]
% Number of user rule types = 1
% Number of user rules = 2
% Before usingLockFile on _build/.shake.lock
% After usingLockFile
% Chunk 0 [len 34] 01000100000000000000040000000100000001000000010000000000000000000000 Id 1 = (StepKey (),Loaded (Result {result = "\SOH\NUL\NUL\NUL", built = Step 1, changed = Step 1, depends = [], execution = 0.0, traces = []}))
% Chunk 1 [len 30] 0a000400000000000000000000000100000001000000728ad03600000000 Id 4 = (alwaysRerun,Loaded (Result {result = "", built = Step 1, changed = Step 1, depends = [], execution = 6.215e-6, traces = []}))
% Chunk 2 [len 66] 080003000000080000005f6275696c642f611400000000000000000000002af6125f03000000010000000100000001000000fd957b39080000000400000004000000 Id 3 = (_build/a,Loaded (Result {result = "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL*\246\DC2_\ETX\NUL\NUL\NUL\SOH\NUL\NUL\NUL", built = Step 1, changed = Step 1, depends = [[Id 4]], execution = 2.39931e-4, traces = []}))
% Chunk 3 [len 66] 080002000000080000005f6275696c642f621400000000000000000000005a937e4d03000000010000000100000001000000a1942b39080000000400000003000000 Id 2 = (_build/b,Loaded (Result {result = "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NULZ\147~M\ETX\NUL\NUL\NUL\SOH\NUL\NUL\NUL", built = Step 1, changed = Step 1, depends = [[Id 3]], execution = 1.63632e-4, traces = []}))
% Chunk 4 [len 50] 000005000000000000000000000001000000010000000000000008000000040000000200000008000000ed872a3aed872a3a Id 5 = (Root,Loaded (Result {result = "", built = Step 1, changed = Step 1, depends = [[Id 2]], execution = 0.0, traces = [Trace {traceMessage = "", traceStart = 6.50524e-4, traceEnd = 6.50524e-4}]}))
% Read 5 chunks, plus 0 slop
% Found at most 6 distinct entries out of 5
% Loaded -> Running, _build/b
% Loaded -> Running, _build/a
% Loaded -> Running, alwaysRerun
% Running -> Ready, alwaysRerun
= ((),"") (changed)
# _build/a
% Running -> Ready, _build/a
= ((Just File {mod=0x5F12F628,size=0x1,digest=NEQ},"")) (unchanged)
% Running -> Ready, _build/b
= ((Just File {mod=0x4D7E9358,size=0x1,digest=NEQ},"")) (changed)
Build completed in 0.00s
Why is _build/b
marked as changed
in this second run?
Upvotes: 0
Views: 55
Reputation: 9250
Shake v0.19.6 had a bug (fixed in 90a52d9) where if a rule didn't rebuild at all it reported (changed)
if the last time the rule ran it changed. In your case, the very first build caused _build/b
to change, so provided _build/b
didn't run again, it would continue to say (changed)
. That's not very useful, so Shake now reports (didn't run)
for rules that didn't run, and that's what it now reports for _build/b
the second time around.
% Running -> Ready, _build/a
= ((Just File {mod=0xE205992F,size=0x1,digest=NEQ},"")) (unchanged)
% Running -> Ready, _build/b
= ((Just File {mod=0xE208A5E4,size=0x1,digest=NEQ},"")) (didn't run)
This bug only impacted the output with trace turned on, internally Shake knows not to continue building, even before this fix.
Upvotes: 1