I'm confused about the rules Shake uses to work out whether an output needs to be rebuilt. I have a simple build for documents with two steps. The full build file is below but to summarise, asciidoc
is used to transform a .txt
file into a .dbxml
(Docbook XML) file, which is then transformed into PDF using dblatex
.
I expect that if I touch the PDF and rerun shake, nothing should happen because the output is newer than both inputs. However, shake in fact executes the dblatex step.
Next, I expect that if I touch the .dbxml
file then shake will execute dblatex but not asciidoc, because the dbxml is newer than its input (i.e. the .txt
). However shake in fact executes both asciidoc and dblatex steps.
Have I made a mistake in my dependencies?
import Development.Shake
import Development.Shake.FilePath
-- List of output files
outputs = ["process.pdf"]
main = shakeArgs shakeOptions{shakeVerbosity=Diagnostic} $ do
want outputs
-- Rule to produce pdf files from dbxml inputs
"*.pdf" *> \out -> do
let dbxml = out `replaceExtension` "dbxml"
need [dbxml]
cmd "dblatex" "-o" out dbxml
-- Rule to produce dbxml files from txt (asciidoc) inputs
"*.dbxml" *> \out -> do
let src = out `replaceExtension` "txt"
need [src]
cmd "asciidoc" "--backend=docbook45" "--doctype=article" "-o" out src
In Shake a file is considered dirty if its last modified time changes from when it was built. In make a file is considered dirty if its last modified time is older than its dependencies. I suspect your observations all stem from this difference. To directly answer the question, Shake rebuilds a file if it or any of its direct dependencies have changed.
Why does Shake do something different to make? Three reasons:
As for your build system, it all looks good to me. My only minor tweak would be the use of the infix operator -<.>
instead of replaceExtension
- they are both the same function but the operator looks clearer to my eye.